Po co definiować create_foo () w modelach Django Managera zamiast nadpisywania create ()?

10

Czytając dokumenty Django , zaleca się utworzenie niestandardowej metody tworzenia modelu o nazwie Foo, definiując go tak jak create_foow menedżerze:

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

Moje pytanie brzmi: dlaczego poprzedni wolałby po prostu przesłonić createmetodę klasy bazowej :

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 wydaje się, że tylko createzastąpienie zapobiegnie przypadkowemu użyciu go do utworzenia źle sformułowanej instancji modelu, ponieważ create_foozawsze można go całkowicie ominąć:

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

Czy jest jakaś korzyść z robienia tego tak, jak sugerują to dokumenty, czy faktycznie jest to createpo prostu obiektywnie lepsze?

ruohola
źródło

Odpowiedzi:

10

Tak, oczywiście, możesz to zrobić. Ale jeśli przyjrzysz się bliżej przykładowi, który zacytowałeś z dokumentacji, nie chodzi o to, czy powinieneś zastąpić tworzenie, czy nie, chodzi o

Jeśli to zrobisz, uważaj, aby nie zmienić podpisu wywołującego, ponieważ każda zmiana może uniemożliwić zapisanie instancji modelu.

zachowanie podpisu wywołującego . Ponieważ dostępne dla ciebie interfejsy mogą być również używane wewnętrznie przez django. Jeśli je zmodyfikujesz, sprawy mogą się nie zepsuć, ale z powodu Django.

W tym przykładzie nie sugerują tego, createale konstruktor modeli.

Po drugie , nawet standardowy interfejs dla createprzyjmuje tylko argumenty słów kluczowych

def create(self, **kwargs):

Ale jeśli zmodyfikujesz go tak, aby przyjmował argumenty pozycyjne, def create(self, title):złamie się wszędzie tam, gdzie jest używany w Django lub w standardowy sposób. Powinieneś więc rozszerzyć istniejącą funkcjonalność, a nie modyfikować i najprawdopodobniej ją zepsuć .

Nafees Anwar
źródło