Por que definir create_foo () em um Django models.Manager em vez de substituir create ()?

10

Lendo os documentos do Django , é recomendável criar um método de criação personalizado para um modelo nomeado Foo, definindo-o como create_foono gerenciador:

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

Minha pergunta é: por que o anterior prefere simplesmente substituir o createmétodo da classe 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, parece que apenas a substituição createimpedirá que alguém a use acidentalmente para criar uma instância de modelo malformada, pois create_foosempre pode ser ignorada completamente:

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

Existe alguma vantagem em fazê-lo como sugerem os documentos ou é realmente substituir createobjetivamente melhor?

ruohola
fonte

Respostas:

10

Sim, obviamente, você pode fazer isso. Mas se você olhar mais de perto o exemplo que está citando da documentação, não se trata de substituir ou não a criação, mas sim

Se você fizer isso, no entanto, tome cuidado para não alterar a assinatura de chamada, pois qualquer alteração pode impedir que a instância do modelo seja salva.

preservando a assinatura de chamada . Porque as interfaces disponíveis para você também podem ser usadas internamente pelo django. Se você modificá-los, as coisas podem não funcionar para você, mas para o Django.

Neste exemplo, eles não estão sugerindo isso para o createconstrutor de modelos.

Em segundo lugar , até a interface padrão createapenas aceita argumentos de palavras-chave

def create(self, **kwargs):

Mas se você modificá-lo para receber argumentos posicionais, def create(self, title):ele será interrompido onde quer que seja usado dentro do Django ou de maneira padrão. Portanto, você deve estender a funcionalidade existente para não modificá-la e provavelmente quebrá- la.

Nafees Anwar
fonte