models.py wird riesig, was ist der beste Weg, um es aufzubrechen?

91

Anweisungen meines Vorgesetzten: "Ich möchte vermeiden, dass Logik in die models.pyDatenbank eingefügt wird. Von nun an verwenden wir diese als einzige Klassen für den Zugriff auf die Datenbank und behalten die gesamte Logik in externen Klassen, die die Modellklassen verwenden, oder umschließen sie."

Ich denke, das ist der falsche Weg. Ich halte es für eine schlechte Idee, die Logik aus den Modellen herauszuhalten, nur um die Datei klein zu halten. Wenn die Logik im Modell am besten ist, sollte sie dort wirklich eingesetzt werden, unabhängig von der Dateigröße.

Gibt es also eine einfache Möglichkeit, Includes zu verwenden? In PHP-Sprache möchte ich dem Supervisor vorschlagen, dass wir nur models.py() die Modellklassen von anderen Orten einbeziehen. Konzeptionell würde dies den Modellen ermöglichen, die gewünschte Logik zu haben und gleichzeitig die Dateigröße durch Erhöhen der Anzahl der Dateien niedrig zu halten (was zu weniger Problemen bei der Revisionskontrolle wie Konflikten usw. führt).

Gibt es eine einfache Möglichkeit, Modellklassen aus der Datei models.py zu entfernen, aber funktionieren die Modelle trotzdem mit allen Django-Tools? Oder gibt es eine völlig andere und dennoch elegante Lösung für das allgemeine Problem einer "großen" Datei models.py? Jede Eingabe wäre dankbar.

Eddifiziert
quelle
7
Sie kennen die Importanweisung, oder?
Balpha
7
PS. Ich meine das nicht offensiv, ich möchte nur wissen, wo du bist.
Balpha
1
Ja, aber ich wusste nicht, ob die Admin-Tools von django funktionieren würden, wenn nur Import-Anweisungen zum Abrufen der Modelle verwendet würden. Ich würde hier lieber fragen, als viel Zeit damit zu verbringen, einfache alte Importe zu verwenden, nur um herauszufinden, dass die Tools von Django nicht gut mit ihnen funktionieren. Ich gebe zu, dass ich neu in Python und Django bin, also bin ich wahrscheinlich nur bei einem einfachen Verständnis der Import-Anweisung ...
Eddified

Antworten:

64

Mit Django können Sie viele kleine Anwendungen anstelle einer großen Anwendung erstellen.

In jeder großen Anwendung gibt es viele kleine Anwendungen, die Schwierigkeiten haben, frei zu sein.

Wenn Sie models.pysich groß fühlen, tun Sie zu viel. Halt. Entspannen. Zersetzen.

Finden Sie kleinere, möglicherweise wiederverwendbare kleine Anwendungskomponenten oder -teile. Sie müssen sie nicht wirklich wiederverwenden. Denken Sie nur an sie als potenziell wiederverwendbar.

Berücksichtigen Sie Ihre Upgrade-Pfade und zerlegen Sie Anwendungen, die Sie möglicherweise eines Tages ersetzen möchten. Sie müssen sie nicht wirklich ersetzen, aber Sie können sie als eigenständiges "Modul" der Programmierung betrachten, das in Zukunft möglicherweise durch etwas Kühleres ersetzt wird.

Wir haben ungefähr ein Dutzend Anwendungen, jede model.pyist nicht mehr als ungefähr 400 Codezeilen. Sie konzentrieren sich alle auf weniger als ein halbes Dutzend diskreter Klassendefinitionen. (Dies sind keine harten Grenzen, sondern Beobachtungen über unseren Code.)

Wir zersetzen uns früh und oft.

S.Lott
quelle
1
genau richtig. Jede nicht triviale Webanwendung wäre mehrere kleine "Apps". Nehmen Sie einen Hinweis auf den Beitrag und andere beliebte Apps, Benutzerauthentifizierung ist eine App, Tagging ist eine andere, Benutzerprofile eine weitere usw.
Javier
4
Dies ist zwar der "richtige" Weg und hilfreich zu wissen, aber nicht ganz das, wonach ich gesucht habe. Ich entschuldige mich, wenn es keine Möglichkeit gab zu wissen, nach welcher Antwort ich suchte. :)
Eddified
@Eddified: Wenn du das nicht tust, wird es nur noch schlimmer. Fangen Sie jetzt an zu teilen.
S.Lott
Komischerweise höre ich gerade Jacob Kaplan Moss (bei OSCON) zu, der genau dies in großen und stark begründeten Details erklärt ;-).
Alex Martelli
13
Die Antwort von Glenn Maynard ist in dieser Frage viel besser. Das Aufteilen einer komplexen Webanwendung in viele Apps ist sicherlich eine gute Vorgehensweise, aber auch das Refactoring einer model.py-Datei INNERHALB einer App. Die beiden Aktionen können orthogonal sein.
Erik
108

Es ist natürlich, dass Modellklassen Methoden enthalten, um das Modell zu bearbeiten. Wenn ich ein Buchmodell habe, mit einer Methodebook.get_noun_count() , gehört es dorthin - ich möchte nicht " get_noun_count(book)" schreiben müssen , es sei denn, die Methode gehört tatsächlich zu einem anderen Paket. (Dies kann beispielsweise der Fall sein, wenn ich ein Paket für den Zugriff auf die Amazon-API mit " get_amazon_product_id(book)" habe.)

Ich zuckte zusammen, als Djangos Dokumentation vorschlug, Modelle in eine einzige Datei zu packen, und ich brauchte von Anfang an ein paar Minuten, um herauszufinden, wie ich sie in ein richtiges Unterpaket aufteilen konnte.

site/models/__init__.py
site/models/book.py

__init__.py sieht aus wie:

from .book import Book

so kann ich immer noch "from site.models import Book" schreiben.


Folgendes ist nur für Versionen vor Django 1.7 erforderlich (siehe https://code.djangoproject.com/ticket/3591)

Der einzige Trick besteht darin, dass Sie die Anwendung jedes Modells aufgrund eines Fehlers in Django explizit festlegen müssen: Es wird davon ausgegangen, dass der Anwendungsname der vorletzte Eintrag im Modellpfad ist. "site.models.Book" führt zu "site", was korrekt ist; "site.models.book.Book" lässt vermuten, dass der Anwendungsname "models" lautet. Dies ist ein ziemlich böser Hack von Djangos Seite; Es sollte wahrscheinlich die Liste der installierten Anwendungen nach einer Präfixübereinstimmung durchsuchen.

class Book(models.Model):
    class Meta: app_label = "site"

Sie könnten wahrscheinlich eine Basisklasse oder eine Metaklasse verwenden, um dies zu verallgemeinern, aber ich habe mich noch nicht darum gekümmert.

Glenn Maynard
quelle
2
+1 Ich habe dies mit Erfolg genutzt. Während S. Lott in mehreren Apps Recht hat, ist dies eine gute Idee, aber dies ist die Hier und Jetzt-Lösung.
Alexander Ljungberg
35
Ich sehe keinen großen Vorteil darin, Dinge in eine Reihe von Apps aufzuteilen, wenn Ihre Modelle eng und eng miteinander verbunden sind.
Glenn Maynard
2
Das interessiert mich. Ich habe den Django-Wiki-Link scompt gelesen und festgestellt: "Dies wurde überprüft, um ohne die Meta-Klasse app_labels im aktuellen Hauptzweig zu funktionieren." Bedeutet das also, wenn Sie mit dem Hauptzweig arbeiten, können wir das Meta: app_label-Zeug verwerfen? Es ist verwirrend, wie es nach dem Kommentar zum Ticket ist, um dieses Problem zu lösen.
Dan.StackOverflow
2
Ich habe gerade mit Kofferraum getestet (seit heute, r11286); Wenn der app_name nicht festgelegt ist, wird das Modell einfach nicht in "sqlall appname" angezeigt und wahrscheinlich nicht von syncdb erstellt (aber ich verwende das nicht, damit ich es nicht testen kann). Es ist ein ziemlich verwirrender Fehlerfall, da er keine Fehler auslöst. es wird nur lautlos nicht angezeigt.
Glenn Maynard
2
Wow, fast 10 Jahre später und ich liebe diese Lösung immer noch. Einverstanden, dass es ein viel besserer Ansatz ist, als Ihren Code in kleinere Apps aufzuteilen, was meiner Meinung nach zu einer Codebasis führen kann, über die man nur schwer nachdenken kann.
Michael Hays
5

Ich kann nicht genau verstehen, welches der vielen möglichen Probleme Sie haben könnten. Hier sind einige Möglichkeiten mit Antworten:

  • mehrere Modelle in derselben Datei

    Legen Sie sie in separate Dateien. Wenn Abhängigkeiten bestehen, verwenden Sie den Import, um die zusätzlichen Modelle abzurufen.

  • Fremdlogik- / Dienstprogrammfunktionen in models.py

    Legen Sie die zusätzliche Logik in separate Dateien.

  • statische Methoden zur Auswahl einiger Modellinstanzen aus der Datenbank

    Erstellen Sie einen neuen Manager in einer separaten Datei.

  • Methoden, die offensichtlich mit dem Modell zusammenhängen

    save, __unicode__ und get_absolute_url sind Beispiele.

hughdbrown
quelle