Django - Overriding the Model.create() method?

DjangoDjango ModelsDjango Forms

Django Problem Overview


The Django docs only list examples for overriding save() and delete(). However, I'd like to define some extra processing for my models only when they are created. For anyone familiar with Rails, it would be the equivalent to creating a :before_create filter. Is this possible?

Django Solutions


Solution 1 - Django

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)

Solution 2 - Django

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.)

Solution 3 - Django

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.

Solution 4 - Django

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.

Solution 5 - Django

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

Solution 6 - Django

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

Solution 7 - Django

The preferred answer is correct but the test to tell whether the object is being created doesn't work if your model derives from UUIDModel. The pk field will already have a value.

In this case, you can do this:

already_created = MyModel.objects.filter(pk=self.pk).exists()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionground5harkView Question on Stackoverflow
Solution 1 - DjangoZachView Answer on Stackoverflow
Solution 2 - DjangoNeuronQView Answer on Stackoverflow
Solution 3 - DjangoMark ChackerianView Answer on Stackoverflow
Solution 4 - DjangoMichael BylstraView Answer on Stackoverflow
Solution 5 - DjangoIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 6 - DjangoRyan AllenView Answer on Stackoverflow
Solution 7 - DjangoJulio CarreraView Answer on Stackoverflow