Pourquoi définir create_foo () dans un models.Manager Django au lieu de remplacer create ()?

10

En lisant les documents Django , il conseille de faire une méthode de création personnalisée pour un modèle nommé Fooen le définissant comme create_foodans le gestionnaire:

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

Ma question est la suivante: pourquoi la précédente est-elle préférable à simplement remplacer la createméthode de la classe de base :

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, il semble que seule la substitution createempêchera quiconque de l'utiliser accidentellement pour créer une instance de modèle mal formée, car elle create_foopeut toujours être contournée complètement:

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

Y a-t-il un avantage à le faire comme le suggèrent les documents, ou est-ce que remplacer est createsimplement mieux objectivement?

ruohola
la source

Réponses:

10

Oui, évidemment, vous pouvez le faire. Mais si vous regardez de plus près l'exemple que vous citez de la documentation, il ne s'agit pas de savoir si vous devez remplacer create ou non, il s'agit de

Dans ce cas, veillez toutefois à ne pas modifier la signature d'appel, car toute modification pourrait empêcher l'enregistrement de l'instance de modèle.

préserver la signature de l'appelant . Parce que les interfaces disponibles pour vous peuvent également être utilisées par django en interne. Si vous les modifiez, les choses peuvent ne pas casser pour vous mais pour Django.

Dans cet exemple, ils ne suggèrent pas cela pour createmais le constructeur du modèle.

Deuxièmement , même l'interface standard pour createne prend que des arguments de mots clés

def create(self, **kwargs):

Mais si vous le modifiez pour prendre des arguments positionnels, def create(self, title):il se brisera partout où il sera utilisé dans Django ou de manière standard. Vous devez donc étendre les fonctionnalités existantes sans les modifier et très probablement les casser .

Nafees Anwar
la source