Teilen Sie models.py in mehrere Dateien auf

87

Ich versuche das zu teilen models.py meine App in mehrere Dateien :

Meine erste Vermutung war, dies zu tun:

myproject/
    settings.py
    manage.py
    urls.py
    __init__.py
    app1/
        views.py
        __init__.py
        models/
            __init__.py
            model1.py
            model2.py
    app2/
        views.py
        __init__.py
        models/
            __init__.py
            model3.py
            model4.py

Das funktioniert nicht, dann fand ich diese , aber in dieser Lösung , die ich habe immer noch ein Problem, wenn ich laufe python manage.py sqlall app1Ich habe so etwas wie:

BEGIN;
CREATE TABLE "product_product" (
    "id" serial NOT NULL PRIMARY KEY,
    "store_id" integer NOT NULL
)
;
-- The following references should be added but depend on non-existent tables:
-- ALTER TABLE "product_product" ADD CONSTRAINT "store_id_refs_id_3e117eef" FOREIGN KEY     ("store_id") REFERENCES "store_store" ("id") DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "product_product_store_id" ON "product_product" ("store_id");
COMMIT;

Ich bin mir da nicht ganz sicher, aber ich mache mir Sorgen um den Teil The following references should be added but depend on non-existent tables:

Dies ist meine model1.py-Datei:

from django.db import models

class Store(models.Model):
    class Meta:
        app_label = "store"

Dies ist meine model3.py-Datei:

from django.db import models

from store.models import Store

class Product(models.Model):
    store = models.ForeignKey(Store)
    class Meta:
        app_label = "product"

Und anscheinend funktioniert es, aber ich habe den Kommentar erhalten alter tableund wenn ich das versuche, passiert dasselbe:

class Product(models.Model):
    store = models.ForeignKey('store.Store')
    class Meta:
        app_label = "product"

Sollte ich die Änderung für Referenzen manuell ausführen? das kann mir Probleme mit dem Süden bringen?

diegueus9
quelle
Was passiert in Modell 3, wenn Sie es versuchen from app1.models.model1 import Store?
James Khoury
Vielleicht möchten Sie auch stackoverflow.com/questions/5534206/…
James Khoury

Antworten:

30

Ich würde folgendes tun:

myproject/
    ...
    app1/
        views.py
        __init__.py
        models.py
        submodels/
            __init__.py
            model1.py
            model2.py
    app2/
        views.py
        __init__.py
        models.py
        submodels/
            __init__.py
            model3.py
            model4.py

Dann

#myproject/app1/models.py:
    from submodels/model1.py import *
    from submodels/model2.py import *

#myproject/app2/models.py:
    from submodels/model3.py import *
    from submodels/model4.py import *

Wenn Sie jedoch keinen guten Grund haben, fügen Sie model1 und model2 direkt in app1 / models.py und model3 und model4 in app2 / models.py ein

---zweiter Teil---

Dies ist die Datei app1 / submodels / model1.py:

from django.db import models
class Store(models.Model):
    class Meta:
        app_label = "store"

Korrigieren Sie daher Ihre model3.py-Datei:

from django.db import models
from app1.models import Store

class Product(models.Model):
    store = models.ForeignKey(Store)
    class Meta:
        app_label = "product"

Bearbeitet, falls dies für jemanden erneut auftritt: Schauen Sie sich den Django-Zeitplan an, um ein Beispiel für ein Projekt zu finden, das genau dies tut. https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/

Ted
quelle
1
In Bezug auf diese Antwort habe ich ein weiteres Problem bekommen, als in models2.py so etwas gemacht wurde wie from product.models import Product: ImportError: Kein Modul namens models
diegueus9
66
Sie würden dies auf diese Weise tun, um eine Klasse pro Datei zu verwalten.
worc
49
Das "Warum" wäre der Wunsch, die Größe einer massiven models.pyDatei zu reduzieren . Ich habe dies kürzlich getan, als meine auf über 15.000 Codezeilen angewachsen ist. Tolles Schreiben. Der Prozess ist ziemlich einfach. Die wichtigste Einschränkung ist, dass Sie daran denken müssen, ein explizites app_label zu definieren, da Django dies standardmäßig aus dem unmittelbaren Modul extrahiert.
Cerin
1
Probieren Sie es 2016 aus. Wird der zweite Teil dieses Beitrags noch benötigt? Ich habe die Klassen nur in separate Dateien verschoben, meine geschrieben __init__.pyund alles scheint in Ordnung zu sein. Ich musste meine Modelldateien nicht korrigieren. Ich kann Objekte aus der Shell und dem Django-Administrator abrufen und erstellen. Ich habe Django seit ungefähr einer Woche ausprobiert, also frage ich mich, ob die neueste Version dies jetzt zulässt.
Vic
2
@Vic: Das app_label in der Meta-Klasse ist bei neueren Versionen von Django nicht mehr erforderlich. Siehe code.djangoproject.com/wiki/CookBookSplitModelsToFiles
jrial
138

Für alle Benutzer von Django 1.9 wird es jetzt vom Framework unterstützt, ohne die Klassen-Metadaten zu definieren.

https://docs.djangoproject.com/de/1.9/topics/db/models/#organizing-models-in-a-package

HINWEIS: Für Django 2 ist es immer noch dasselbe

Der manage.py startappBefehl erstellt eine Anwendungsstruktur, die eine Datei models.py enthält. Wenn Sie viele Modelle haben, kann es hilfreich sein, diese in separaten Dateien zu organisieren.

Erstellen Sie dazu ein Modellpaket. Entfernen Sie models.py und erstellen Sie ein myapp/models/Verzeichnis mit einer __init__.pyDatei und den Dateien zum Speichern Ihrer Modelle. Sie müssen die Modelle in die __init__.pyDatei importieren .

Also in Ihrem Fall für eine Struktur wie

app1/
    views.py
    __init__.py
    models/
        __init__.py
        model1.py
        model2.py
app2/
    views.py
    __init__.py
    models/
        __init__.py
        model3.py
        model4.py

Sie müssen nur tun

#myproject/app1/models/__init__.py:
from .model1 import Model1
from .model2 import Model2

#myproject/app2/models/__init__.py:
from .model3 import Model3
from .model4 import Model4

Ein Hinweis gegen den Import aller Klassen:

Das explizite Importieren jedes Modells anstelle der Verwendung from .models import *hat den Vorteil, dass der Namespace nicht überladen wird, der Code lesbarer wird und die Tools zur Codeanalyse nützlich bleiben.

Vic
quelle
4
Falls sich jemand fragt, ob es mit Django 2.0 docs.djangoproject.com/de/2.0/topics/db/models/…
NaturalBornCamper am
6
HINWEIS: Dies funktioniert normalerweise nicht ordnungsgemäß, wenn Sie mit begonnen haben models.pyund später migrieren möchten. In diesem Fall müssen Sie Ihre Migrationen und Ihre Datenbank löschen: / Oder um alle Fehler in allen Migrationsdateien manuell zu beheben
tuergeist
Beste Antwort noch. Kann bestätigen, dass dies immer noch in 2.1+ funktioniert
Roys
Ich sehe das Problem, auf das @tuergeist in Django 3.0 hingewiesen hat, nicht. Scheint
Karam
11

Ich habe tatsächlich ein Tutorial für genau das gefunden, wonach Sie fragen. Sie können es hier ansehen:

http://paltman.com/breaking-apart-models-in-django/

Ein wichtiger Punkt, der wahrscheinlich relevant ist: Möglicherweise möchten Sie das Feld db_table in der Meta-Klasse verwenden, um die verschobenen Klassen wieder auf ihre eigene Tabelle zu verweisen.

Ich kann bestätigen, dass dieser Ansatz in Django 1.3 funktioniert

Adam Luchjenbroers
quelle
Dieser Link gibt eine 404
Bryan Oakley
1

Einfachste Schritte:

  1. Modellordner in Ihrer App erstellen (Ordnername sollte Modell sein )
  2. Löschen Sie die Datei model.py aus dem App-Verzeichnis (Sichern Sie die Datei, während Sie sie löschen).
  3. Und nach dem Erstellen der init .py-Datei im Modellordner
  4. Und nach init .py-Datei schreiben Sie einfach eine Zeile
  5. Nach dem Erstellen der Modelldatei in Ihrem Modellordner sollte der Name der Modelldatei mit dem Klassennamen identisch sein. Wenn der Klassenname "Employee" lautet , sollte der Name der Modelldatei "employee.py" lauten.
  6. Und nachdem Sie in der Modelldatei Ihre Datenbanktabelle definiert haben, schreiben Sie sie wie in der Datei model.py
  7. Speichern Sie es

Mein Code: von django_adminlte.models.employee import Employee

Für Ihre: von app_name .models. model_file_name_only importiere Class_Name_which_define_in_model_file


__init__.py

from django_adminlte.models.employee import Employee

model/employee.py (employee is separate model file)

from django.db import models

class Employee(models.Model):
eid = models.CharField(max_length=20)
ename = models.CharField(max_length=20)
eemail = models.EmailField()
econtact = models.CharField(max_length=15)

class Meta:
    db_table = "employee"
    # app_label = 'django_adminlte'
    
def __str__(self):
    return self.ename
Parth Jani
quelle
2
Genau das versucht er zu beheben. Diese Lösung wird RuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.in Django 2.x verursachen .
Radtek
0

Ich habe ein Skript geschrieben, das nützlich sein könnte.

github.com/victorqribeiro/splitDjangoModels

Es teilt die Modelle in einzelne Dateien mit der richtigen Benennung und dem richtigen Import auf. Außerdem wird eine Init-Datei erstellt, sodass Sie alle Ihre Modelle gleichzeitig importieren können.

Lassen Sie mich wissen, ob das hilft

user1659565
quelle