Dividi models.py in più file


89

Sto cercando di dividere la models.pydella mia app in diversi file:

La mia prima ipotesi è stata fare questo:

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

Questo non funziona, quindi ho trovato questo , ma in questa soluzione ho ancora un problema, quando corro python manage.py sqlall app1ho ottenuto qualcosa del tipo:

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;

Non ne sono abbastanza sicuro, ma sono preoccupato per la parte The following references should be added but depend on non-existent tables:

Questo è il mio file model1.py:

from django.db import models

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

Questo è il mio file model3.py:

from django.db import models

from store.models import Store

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

E a quanto pare funziona, ma ho ricevuto il commento alter tablee se provo questo, succede la stessa cosa:

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

Quindi, dovrei eseguire l'alterazione per i riferimenti manualmente? questo potrebbe portarmi problemi con il sud?


Cosa succede nel modello 3 se ci provi from app1.models.model1 import Store?
James Khoury

Inoltre potresti voler controllare stackoverflow.com/questions/5534206/…
James Khoury,

Risposte:


32

Farei quanto segue:

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

Poi

#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 *

Ma, se non hai una buona ragione, metti model1 e model2 direttamente in app1 / models.py e model3 e model4 in app2 / models.py

---seconda parte---

Questo è il file app1 / submodels / model1.py:

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

Quindi correggi il tuo file model3.py:

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

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

Modificato, nel caso in cui qualcuno si ripresenti: dai un'occhiata a django-schedule per un esempio di un progetto che fa proprio questo. https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/


1
Rispetto a questa risposta ho un altro problema quando in models2.py creo qualcosa di simile from product.models import Product: ImportError: Nessun modulo denominato models
diegueus9

68
lo faresti in questo modo per mantenere una classe per file.
worc

50
Il "perché" sarebbe il desiderio di ridurre le dimensioni di un models.pyfile enorme . Recentemente l'ho fatto quando il mio è cresciuto fino a superare le 15k righe di codice. Ottimo commento però. Il processo è abbastanza semplice. L'avvertenza principale è che devi ricordarti di definire un'etichetta app_label esplicita, poiché Django la estrae dal modulo immediato per impostazione predefinita.
Cerin

1
Fare un tentativo nel 2016. È ancora necessaria la seconda parte di questo post? Ho solo spostato le classi in file separati, ho scritto il mio __init__.pye tutto sembra funzionare bene. Non ho dovuto correggere i miei file di modello. Sono in grado di recuperare e creare oggetti dalla shell e dall'amministratore di django. Ho provato django per una settimana, quindi mi chiedo se la versione più recente ora consente che ciò accada?
Vic

3
@Vic: l'app_label nella classe Meta non è più necessaria con le versioni più recenti di Django. Vedi code.djangoproject.com/wiki/CookBookSplitModelsToFiles
jrial

147

Per chiunque su Django 1.9, ora è supportato dal framework senza definire i metadati della classe.

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

NOTA: per Django 2, è sempre lo stesso

Il manage.py startappcomando crea una struttura dell'applicazione che include un file models.py. Se hai molti modelli, può essere utile organizzarli in file separati.

Per fare ciò, crea un pacchetto di modelli. Rimuovi models.py e crea una myapp/models/directory con un __init__.pyfile e i file per memorizzare i tuoi modelli. È necessario importare i modelli nel __init__.pyfile.

Quindi, nel tuo caso, per una struttura come

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

Hai solo bisogno di fare

#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

Una nota contro l'importazione di tutte le classi:

L'importazione esplicita di ogni modello anziché l'utilizzo from .models import *ha il vantaggio di non ingombrare lo spazio dei nomi, rendere il codice più leggibile e mantenere utili gli strumenti di analisi del codice.


5
Nel caso in cui qualcuno si chiede se è ancora al passo con Django 2.0 docs.djangoproject.com/en/2.0/topics/db/models/...
NaturalBornCamper

6
NOTA: di solito non funziona correttamente quando si è iniziato models.pye si desidera eseguire la migrazione in un secondo momento. In tal caso, devi eliminare le tue migrazioni e il tuo database: / O per risolvere manualmente tutti gli errori in tutti i file di migrazione
tuergeist

Migliore risposta ancora. Posso confermare che funziona ancora in 2.1+
Roys

Non vedo il problema segnalato da @tuergeist in Django 3.0. Sembra funzionare come un incantesimo
caram il

11

In realtà mi sono imbattuto in un tutorial per esattamente quello che stai chiedendo, puoi vederlo qui:

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

Un punto chiave che probabilmente è rilevante: potresti voler utilizzare il campo db_table sulla classe Meta per indirizzare le classi riposizionate alla propria tabella.

Posso confermare che questo approccio funziona in Django 1.3


Quel collegamento dà un 404
Bryan Oakley

1

Passaggi più semplici:

  1. Crea la cartella del modello nella tua app (il nome della cartella dovrebbe essere il modello )
  2. Elimina il file model.py dalla directory dell'app ( esegui il backup del file mentre lo elimini)
  3. E dopo aver creato il file init .py nella cartella del modello
  4. E dopo il file init .py scrivi una riga semplice
  5. E dopo aver creato il file del modello nella cartella del modello e il nome del file del modello dovrebbe essere lo stesso del nome della classe, se il nome della classe è "Dipendente", il nome del file del modello dovrebbe essere come "dipendente.py"
  6. E dopo nel file modello, definire la tabella del database come scrivi come nel file model.py
  7. Salvarla

Il mio codice: da django_adminlte.models.employee import Employee

Per il tuo: da app_name .models. model_file_name_only importa 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

2
Questo è esattamente ciò che sta cercando di risolvere. Questa soluzione provocherà RuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.in django 2.x.
radtek

0

Ho scritto uno script che potrebbe essere utile.

github.com/victorqribeiro/splitDjangoModels

suddivide i modelli in file individuali con una corretta denominazione e importazione; crea anche un file init così puoi importare tutti i tuoi modelli contemporaneamente.

fammi sapere se questo aiuta

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.