Django - Overriding the Model.create() method?

后端 未结 7 930
忘了有多久
忘了有多久 2020-12-04 08:36

The Django docs only list examples for overriding save() and delete(). However, I\'d like to define some extra processing for my models onl

相关标签:
7条回答
  • 2020-12-04 09:21

    To answer the question literally, the create method in a model's manager is a standard way to create new objects in Django. To override, do something like

    from django.db import models
    
    class MyModelManager(models.Manager):
        def create(self, **obj_data):
            # Do some extra stuff here on the submitted data before saving...
            # For example...
            obj_data['my_field'] = my_computed_value(obj_data['my_other_field'])
    
            # Now call the super method which does the actual creation
            return super().create(**obj_data) # Python 3 syntax!!
    
    class MyModel(models.model):
        # An example model
        my_field = models.CharField(max_length=250)
        my_other_field = models.CharField(max_length=250)
    
        objects = MyModelManager()
    

    In this example, I'm overriding the Manager's method create method to do some extra processing before the instance is actually created.

    NOTE: Code like

    my_new_instance = MyModel.objects.create(my_field='my_field value')

    will execute this modified create method, but code like

    my_new_unsaved_instance = MyModel(my_field='my_field value')

    will not.

    0 讨论(0)
  • 2020-12-04 09:32

    This is old, has an accepted answer that works (Zach's), and a more idiomatic one too (Michael Bylstra's), but since it's still the first result on Google most people see, I think we need a more best-practices modern-django style answer here:

    from django.db.models.signals import post_save
    
    class MyModel(models.Model):
        # ...
        @classmethod
        def post_create(cls, sender, instance, created, *args, **kwargs):
            if not created:
                return
            # ...what needs to happen on create
    
    post_save.connect(MyModel.post_create, sender=MyModel)
    

    The point is this:

    1. use signals (read more here in the official docs)
    2. use a method for nice namespacing (if it makes sense) ...and I marked it as @classmethod instead of @staticmethod because most likely you'll end up needing to refer static class members in the code

    Even cleaner would be if core Django would have an actual post_create signal. (Imho if you need to pass a boolean arg to change behavior of a method, that should be 2 methods.)

    0 讨论(0)
  • 2020-12-04 09:34

    an example of how to create a post_save signal (from http://djangosnippets.org/snippets/500/)

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    @receiver(post_save, sender=User)
    def create_profile(sender, instance, created, **kwargs):
        """Create a matching profile whenever a user object is created."""
        if created: 
            profile, new = UserProfile.objects.get_or_create(user=instance)
    

    here is a thoughtful discussion on whether it's best to use signals or custom save methods https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/

    In my opinion using signals for this task is more robust, easier to read but lengthier.

    0 讨论(0)
  • 2020-12-04 09:36

    You can override the create method with a custom manager or add a classmethod on the model class. https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects

    0 讨论(0)
  • 2020-12-04 09:41

    Overriding __init__() would cause code to be executed whenever the python representation of object is instantiated. I don't know rails, but a :before_created filter sounds to me like it's code to be executed when the object is created in the database. If you want to execute code when a new object is created in the database, you should override save(), checking if the object has a pk attribute or not. The code would look something like this:

    def save(self, *args, **kwargs):
        if not self.pk:
            # This code only happens if the objects is
            # not in the database yet. Otherwise it would
            # have pk
        super(MyModel, self).save(*args, **kwargs)
    
    0 讨论(0)
  • 2020-12-04 09:41

    Overriding __init__() will allow you to execute code when the model is instantiated. Don't forget to call the parent's __init__().

    0 讨论(0)
提交回复
热议问题