Divisez models.py en plusieurs fichiers

89

J'essaye de diviser le models.pyde mon application en plusieurs fichiers:

Ma première hypothèse était de faire ceci:

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

Cela ne fonctionne pas, alors j'ai trouvé cela , mais dans cette solution, j'ai toujours un problème, quand je cours, python manage.py sqlall app1j'ai quelque chose comme:

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;

Je ne suis pas sûr de ça, mais je m'inquiète pour la partie The following references should be added but depend on non-existent tables:

Ceci est mon fichier model1.py:

from django.db import models

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

Ceci est mon fichier 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"

Et fonctionne apparemment mais j'ai reçu le commentaire alter tableet si j'essaye ceci, la même chose se produit:

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

Alors, dois-je exécuter l'alter pour les références manuellement? cela peut me poser des problèmes avec le sud?

diegueus9
la source
Que se passe-t-il dans le modèle 3 si vous essayez from app1.models.model1 import Store?
James Khoury
Vous voudrez peut-être aussi consulter stackoverflow.com/questions/5534206/…
James Khoury

Réponses:

32

Je ferais ce qui suit:

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

ensuite

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

Mais, si vous n'avez pas de bonne raison, placez model1 et model2 directement dans app1 / models.py et model3 et model4 dans app2 / models.py

---deuxième partie---

Il s'agit du fichier app1 / submodels / model1.py:

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

Corrigez donc votre fichier 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"

Modifié, au cas où cela se reproduirait pour quelqu'un: consultez django-schedule pour un exemple de projet qui fait exactement cela. https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/

Ted
la source
1
En ce qui concerne cette réponse, j'ai eu un autre problème lorsque dans models2.py, faites quelque chose comme from product.models import Product: ImportError: Aucun module nommé models
diegueus9
68
vous le feriez de cette façon pour conserver une classe par fichier.
worc
50
Le «pourquoi» serait le désir de réduire la taille d'un models.pyfichier volumineux . J'ai récemment fait cela lorsque le mien est passé à plus de 15 000 lignes de code. Excellent article cependant. Le processus est assez simple. La principale mise en garde étant que vous devez vous rappeler de définir un app_label explicite, car Django extrait cela du module immédiat par défaut.
Cerin
1
J'essaye ça en 2016. La deuxième partie de ce post est-elle encore nécessaire? J'ai seulement déplacé les classes vers des fichiers séparés, écrit mon __init__.pyet tout semble fonctionner correctement. Je n'ai pas eu à corriger mes fichiers modèles. Je suis capable de récupérer et de créer des objets à partir du shell et de l'administrateur django. J'essaye django depuis une semaine, alors je me demande si la dernière version permet maintenant que cela se produise?
Vic
3
@Vic: Le app_label dans la classe Meta n'est plus nécessaire avec les nouvelles versions de Django. Voir code.djangoproject.com/wiki/CookBookSplitModelsToFiles
jrial
147

Pour quiconque sur Django 1.9, il est désormais pris en charge par le framework sans définir les métadonnées de classe.

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

NOTE: pour Django 2, c'est toujours la même

le manage.py startapp commande crée une structure d'application qui inclut un fichier models.py. Si vous possédez de nombreux modèles, il peut être utile de les organiser dans des fichiers séparés.

Pour ce faire, créez un package de modèles. Supprimez models.py et créez un myapp/models/répertoire avec un __init__.pyfichier et les fichiers pour stocker vos modèles. Vous devez importer les modèles dans le __init__.pyfichier.

Donc, dans votre cas, pour une structure comme

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

Il suffit de faire

#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

Une note contre l'importation de toutes les classes:

L'importation explicite de chaque modèle plutôt que l'utilisation from .models import *présente les avantages de ne pas encombrer l'espace de noms, de rendre le code plus lisible et de garder les outils d'analyse de code utiles.

Vic
la source
5
Au cas où quelqu'un se demanderait s'il est toujours à jour avec Django 2.0 docs.djangoproject.com/en/2.0/topics/db/models
...
6
REMARQUE: Cela ne fonctionne généralement pas correctement lorsque vous avez commencé models.pyet que vous souhaitez migrer plus tard. Dans ce cas, vous devez supprimer vos migrations et votre base de données: / Ou résoudre manuellement toutes les erreurs dans tous les fichiers de migration
tuergeist
Meilleure réponse encore. Peut confirmer que cela fonctionne toujours dans 2.1+
Roys
Je ne vois pas le problème signalé par @tuergeist dans Django 3.0. Semble fonctionner comme un charme
caram
11

En fait, je suis tombé sur un tutoriel pour exactement ce que vous demandez, vous pouvez le voir ici:

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

Un point clé qui est probablement pertinent - vous pouvez utiliser le champ db_table sur la classe Meta pour renvoyer les classes déplacées vers leur propre table.

Je peux confirmer que cette approche fonctionne dans Django 1.3

Adam Luchjenbroers
la source
Ce lien donne un 404
Bryan Oakley
1

Étapes les plus faciles:

  1. Créez un dossier de modèle dans votre application (le nom du dossier doit être model )
  2. Supprimer le fichier model.py du répertoire de l'application (sauvegarder le fichier pendant que vous le supprimez)
  3. Et après créer le fichier init .py dans le dossier modèle
  4. Et après init fichier .py en écriture simple sur une ligne
  5. Et après avoir créé le fichier de modèle dans votre dossier de modèle et le nom de fichier de modèle doit être identique au nom de la classe, si le nom de la classe est «Employé», le nom du fichier du modèle doit être comme «employé.py»
  6. Et après dans le fichier modèle, définissez votre table de base de données de la même manière que dans le fichier model.py
  7. Sauvegarde le

Mon code: de django_adminlte.models.employee import Employé

Pour votre: from app_name .models. model_file_name_only import 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
la source
2
C'est exactement ce qu'il essaie de réparer. Cette solution provoquera RuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.dans django 2.x.
radtek
0

J'ai écrit un script qui pourrait être utile.

github.com/victorqribeiro/splitDjangoModels

il divise les modèles en fichiers individuels avec un nom et une importation appropriés; il crée également un fichier init afin que vous puissiez importer tous vos modèles à la fois.

laissez-moi savoir si cela aide

user1659565
la source