Django - Overriding the Model.create() method?
DjangoDjango ModelsDjango FormsDjango 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:
- use signals (read more here in the official docs)
- 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()