Reading the Django docs, it advices to make a custom creation method for a model named Foo
by defining it as create_foo
in the manager:
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create_book("Pride and Prejudice")
My question is that why is the previous one preferred to simply overriding the base class's create
method:
class BookManager(models.Manager):
def create(self, title):
book = self.model(title=title)
# do something with the book
book.save()
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create("Pride and Prejudice")
Imo it seems that only overriding create
will prevent anyone from accidentally using it to make a illformed model instance, since create_foo
can always be bypassed completely:
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title, should_not_be_set_manually="critical text")
return book
class Book(models.Model):
title = models.CharField(max_length=100)
should_not_be_set_manually = models.CharField(max_length=100)
objects = BookManager()
# Can make an illformed Book!!
book = Book.objects.create(title="Some title", should_not_be_set_manually="bad value")
Is there any advantage in doing it like the docs suggest, or is actually overriding create
just objectively better?
Yes, obviously, you can do that. But if you look closer to the example you are quoting from documentation, it is not about whether you should override create or not, it is about
If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved.
preserving the calling signature. Because interfaces available for you may also be used by django internally. If you modify them, things may not break for you but for Django.
In this example, they are not suggesting this for create
but model constructor.
Secondly, even standard interface for create
is only taking keyword arguments
def create(self, **kwargs):
But if you modify it to take positional arguments, def create(self, title):
it will break wherever it is used inside Django or in standard way. So you should extend existing functionality not modify and most probably break it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With