为什么要在Django models.Manager中定义create_foo()而不是覆盖create()?


10

阅读Django文档后,建议Foo通过create_foo在管理器中定义模型来为命名模型创建自定义创建方法:

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

我的问题是,为什么前一个方法更喜欢简单地重写基类的create方法:

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似乎只有重写create才能防止任何人意外地使用它来制作格式不正确的模型实例,因为create_foo始终可以完全绕开它:

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

这样做是否有任何好处,如文档所建议的那样,或者实际上create是客观上更好地覆盖了它?

Answers:


10

是的,显然,您可以做到。但是,如果您更仔细地看文档中引用的示例,则与您是否应覆盖create无关,而与

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

保留呼叫签名。因为django内部还可以使用可供您使用的接口。如果您对其进行修改,那么对于Django而言,事情可能不会对您不利。

在此示例中,他们不建议这样做,create而是模型构造函数。

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

def create(self, **kwargs):

但是,如果您修改它以接受位置参数,def create(self, title):则无论它在Django内部或以标准方式使用的位置,它都会中断。因此,您应该扩展现有功能而不进行修改,并且很有可能破坏它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.