Зачем определять create_foo () в моделях Django. Менеджер вместо переопределения 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")

Похоже, что только переопределение 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просто объективно лучше?

Руохола
источник

Ответы:

10

Да, очевидно, вы можете сделать это. Но если вы посмотрите ближе на пример, который вы цитируете из документации, это не о том, следует ли вам переопределить создание или нет, это о

Однако, если вы сделаете это, позаботьтесь о том, чтобы не изменять подпись вызывающего, так как любое изменение может помешать сохранению экземпляра модели.

сохранение вызывающей подписи . Поскольку доступные для вас интерфейсы также могут использоваться django для внутренних целей. Если вы измените их, вещи могут сломаться не для вас, а для Джанго.

В этом примере они предлагают не это, createа конструктор модели.

Во-вторых , даже стандартный интерфейс для createпринимает только ключевые аргументы

def create(self, **kwargs):

Но если вы измените его так, чтобы он принимал позиционные аргументы, def create(self, title):он сломается везде, где он используется внутри Django или стандартным способом. Таким образом, вы должны расширять существующую функциональность, а не изменять и, скорее всего, нарушать ее.

Нафиш Анвар
источник