djangodjango-models

Pass save parameter through Django create method


Let's say I have the following Django model, which overrides the save method:

class Person(models.Model):
    name = models.CharField(max_length=50)

    def save(self, lock=False, *args, **kwargs):
        if lock:
            print("LOCKING OBJECT...")
        super().save(*args, **kwargs)

I know I can create a person and pass lock to the save method like so:

steve = Person(name="Steve")
steve.save(lock=True)
# LOCKING OBJECT...

However, I really enjoy using the create method, as it's much more readable:

Person.objects.create(name="Michelle")

How can I pass lock using the latter approach? The following doesn't work:

Person.objects.create(name="Michelle", lock=True)
# TypeError: Person() got an unexpected keyword argument 'lock'

Solution

  • You can add additional methods to the Person manager (the objects object) by creating a custom manager for your model:

    class PersonManager(models.Manager):
    
        def create_person(self, *args, **kwargs):
            lock = kwargs.pop('lock', False)
            new_person = self.model(**kwargs)
            new_person.save(lock=lock)
            return new_person
    

    Then add that new manager to your model:

    class Person(models.Model):
    
        name = models.CharField(max_length=50)
    
        objects = PersonManager() # Here we refer to the newly created manager
    
        def save(self, lock=False, *args, **kwargs):
            if lock:
                print("LOCKING OBJECT...")
            super().save(*args, **kwargs)
    

    Now you can call:

    Person.objects.create_person(name='Pablo', lock=True)
    

    You can also override the function name create but that could have unintended effects, so I wouldn't.

    Note that this is a common pattern in Django apps, like Auth.