Why define create_foo() in a Django models.Manager instead of overriding create()?

ruo*_*ola 10 python django django-models django-managers

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")
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

Is there any advantage in doing it like the docs suggest, or is actually overriding create just objectively better?

Naf*_*war 11

是的,很明显,你可以做到。但是,如果您仔细观察您从文档中引用的示例,这不是关于您是否应该覆盖 create ,而是关于

但是,如果这样做,请注意不要更改调用签名,因为任何更改都可能会阻止保存模型实例。

保留调用签名。因为可供您使用的接口也可能在 django 内部使用。如果你修改它们,事情可能不会对你造成影响,但对 Django 而言。

在这个例子中,他们建议的不是create模型构造函数,而是模型构造函数。

其次,即使是标准接口 forcreate也只接受关键字参数

def create(self, **kwargs):
Run Code Online (Sandbox Code Playgroud)

但是如果你修改它以接受位置参数,def create(self, title):它会在 Django 内部或以标准方式使用的任何地方中断。所以你应该扩展现有的功能而不是修改并且很可能破坏它。