Dividir models.py en varios archivos

89

Estoy tratando de dividir el models.pyde mi aplicación en varios archivos:

Mi primera suposición fue hacer esto:

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

Esto no funciona, luego encontré esto , pero en esta solución todavía tengo un problema, cuando ejecuto python manage.py sqlall app1tengo algo como:

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;

No estoy muy seguro de esto, pero estoy preocupado por la parte The following references should be added but depend on non-existent tables:

Este es mi archivo model1.py:

from django.db import models

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

Este es mi archivo 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"

Y aparentemente funciona, pero recibí el comentario alter tabley si intento esto, sucede lo mismo:

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

Entonces, ¿debería ejecutar el alter para referencias manualmente? esto puede traerme problemas con el sur?

diegueus9
fuente
¿Qué pasa en el modelo 3 si lo intentas from app1.models.model1 import Store?
James Khoury
También es posible que desee consultar stackoverflow.com/questions/5534206/…
James Khoury

Respuestas:

32

Haría lo siguiente:

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

Entonces

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

Pero, si no tiene una buena razón, coloque model1 y model2 directamente en app1 / models.py y model3 y model4 en app2 / models.py

---segunda parte---

Este es el archivo app1 / submodels / model1.py:

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

Por lo tanto, corrija su archivo 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"

Editado, en caso de que esto vuelva a surgir para alguien: consulte django-schedule para ver un ejemplo de un proyecto que hace exactamente esto. https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/

Ted
fuente
1
Con respecto a esta respuesta, tengo otro problema cuando en models2.py hago algo como from product.models import Product: ImportError: Ningún módulo llamado modelos
diegueus9
68
lo haría de esta manera para mantener una clase por archivo.
Trabajo
50
El "por qué" sería el deseo de reducir el tamaño de un models.pyarchivo masivo . Recientemente hice esto cuando el mío creció a más de 15k líneas de código. Sin embargo, gran reseña. El proceso es bastante sencillo. La principal advertencia es que debes recordar definir un app_label explícito, ya que Django lo extrae del módulo inmediato de forma predeterminada.
Cerin
1
Probando esto en 2016. ¿Todavía se necesita la segunda parte de esta publicación? Solo moví las clases a archivos separados, escribí mi __init__.pyy todo parece estar funcionando bien. No tuve que corregir mis archivos de modelo. Puedo buscar y crear objetos desde el shell y el administrador de django. He estado probando django durante una semana, así que me pregunto si la versión más nueva ahora permite que esto suceda.
Vic
3
@Vic: App_label en la clase Meta ya no es necesaria con las versiones más recientes de Django. Ver code.djangoproject.com/wiki/CookBookSplitModelsToFiles
jrial
147

Para cualquiera en Django 1.9, ahora es compatible con el marco sin definir los metadatos de la clase.

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

NOTA: Para Django 2, sigue siendo el mismo

El manage.py startappcomando crea una estructura de aplicación que incluye un archivo models.py. Si tiene muchos modelos, organizarlos en archivos separados puede resultar útil.

Para hacerlo, cree un paquete de modelos. Elimina models.py y crea un myapp/models/directorio con un __init__.pyarchivo y los archivos para almacenar tus modelos. Debe importar los modelos en el __init__.pyarchivo.

Entonces, en su caso, para una estructura como

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

Solo necesitas hacer

#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 contra la importación de todas las clases:

Importar explícitamente cada modelo en lugar de usar from .models import *tiene las ventajas de no saturar el espacio de nombres, hacer que el código sea más legible y mantener las herramientas de análisis de código útiles.

Vic
fuente
5
En caso de que alguien se pregunte si todavía está actualizado con Django 2.0 docs.djangoproject.com/en/2.0/topics/db/models/…
NaturalBornCamper
6
NOTA: Por lo general, esto no funciona correctamente cuando ha comenzado models.pyy desea migrar más tarde. En ese caso, debe eliminar sus migraciones y su base de datos: / O resolver manualmente todos los errores en todos los archivos de migración
tuergeist
Aún mejor respuesta. Puedo confirmar que esto todavía funciona en 2.1+
Roys
No veo el problema señalado por @tuergeist en Django 3.0. Parece funcionar como un encanto
caram
11

De hecho, me encontré con un tutorial para exactamente lo que está preguntando, puede verlo aquí:

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

Un punto clave que probablemente sea relevante: es posible que desee utilizar el campo db_table en la clase Meta para señalar las clases reubicadas de nuevo en su propia tabla.

Puedo confirmar que este enfoque está funcionando en Django 1.3

Adam Luchjenbroers
fuente
Ese enlace da un 404
Bryan Oakley
1

Pasos más sencillos:

  1. Cree una carpeta de modelo en su aplicación (el nombre de la carpeta debe ser el modelo )
  2. Elimine el archivo model.py del directorio de la aplicación ( haga una copia de seguridad del archivo mientras lo elimina)
  3. Y después de crear el archivo init .py en la carpeta del modelo
  4. Y después del archivo init .py en escribir una línea simple
  5. Y después de crear el archivo del modelo en la carpeta del modelo y el nombre del archivo del modelo debe ser el mismo que el nombre de la clase, si el nombre de la clase es 'Empleado', el nombre del archivo del modelo debe ser como 'empleado.py'
  6. Y después, en el archivo modelo, defina la tabla de su base de datos igual que escribir como en el archivo model.py
  7. Guárdalo

Mi código: de django_adminlte.models.employee import Employee

Para su: de 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
fuente
2
Esto es exactamente lo que está tratando de arreglar. Esta solución provocará RuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.en django 2.x.
radtek
0

Escribí un guión que podría ser útil.

github.com/victorqribeiro/splitDjangoModels

dividió los modelos en archivos individuales con el nombre y la importación adecuados; también crea un archivo de inicio para que pueda importar todos sus modelos a la vez.

Déjeme saber si esto ayuda

usuario1659565
fuente