Divida models.py em vários arquivos


91

Estou tentando dividir o models.pydo meu aplicativo em vários arquivos:

Meu primeiro palpite foi fazer isto:

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

Isso não funciona, então eu achei isso , mas nesta solução ainda tenho um problema, quando eu executo python manage.py sqlall app1eu tenho 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;

Não tenho certeza sobre isso, mas estou preocupado com a parte The following references should be added but depend on non-existent tables:

Este é meu arquivo model1.py:

from django.db import models

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

Este é meu arquivo 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 aparentemente funciona, mas eu tenho o comentário alter tablee se eu tentar isso, acontece a mesma coisa:

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

Portanto, devo executar o alter para referências manualmente? isso pode me trazer problemas com o sul?


O que acontece no modelo 3 se você tentar from app1.models.model1 import Store?
— James Khoury de

Além disso, você pode querer verificar stackoverflow.com/questions/5534206/…
— James Khoury

Respostas:


33

Eu faria o seguinte:

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

Então

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

Mas, se você não tiver um bom motivo, coloque model1 e model2 diretamente em app1 / models.py e model3 e model4 em app2 / models.py

---segunda parte---

Este é o arquivo app1 / submodels / model1.py:

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

Portanto, corrija seu arquivo 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, caso isso aconteça novamente para alguém: Verifique django-schedule para ver um exemplo de projeto que faz exatamente isso. https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/


1
Com relação a esta resposta eu tenho outro problema quando em models2.py faço algo como from product.models import Product: ImportError: Nenhum módulo chamado models
— diegueus9

68
você faria isso dessa maneira para manter uma classe por arquivo.
— worc

50
O "porquê" seria o desejo de reduzir o tamanho de um models.pyarquivo enorme . Recentemente fiz isso quando o meu cresceu para mais de 15 mil linhas de código. Grande redação embora. O processo é bastante simples. A principal advertência é que você deve se lembrar de definir um app_label explícito, já que o Django extrai isso do módulo imediato por padrão.
— Cerin

1
Experimentando em 2016. A segunda parte deste post ainda é necessária? Eu apenas movi as classes para arquivos separados, escrevi o meu __init__.pye tudo parece estar funcionando bem. Não precisei corrigir meus arquivos de modelo. Sou capaz de buscar e criar objetos do shell e do administrador django. Estou tentando django há uma semana, então estou me perguntando se a versão mais recente agora permite que isso aconteça.
— Vic

3
@Vic: O app_label na classe Meta não é mais necessário com as versões mais recentes do Django. Consulte code.djangoproject.com/wiki/CookBookSplitModelsToFiles
— jrial

149

Para qualquer pessoa no Django 1.9, agora é suportado pelo framework sem definir os metadados da classe.

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

NOTA: Para Django 2, ainda é o mesmo

O manage.py startappcomando cria uma estrutura de aplicativo que inclui um arquivo models.py. Se você tiver muitos modelos, organizá-los em arquivos separados pode ser útil.

Para fazer isso, crie um pacote de modelos. Remova models.py e crie ummyapp/models/ diretório com um __init__.pyarquivo e os arquivos para armazenar seus modelos. Você deve importar os modelos no __init__.pyarquivo.

Então, no seu caso, para uma estrutura 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

Você só precisa fazer

#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

Uma observação contra a importação de todas as classes:

Importar explicitamente cada modelo em vez de usar from .models import *tem as vantagens de não sobrecarregar o namespace, tornando o código mais legível e mantendo as ferramentas de análise de código úteis.


6
Caso alguém esteja se perguntando se ele ainda está atualizado com o Django 2.0 docs.djangoproject.com/en/2.0/topics/db/models/…
— NaturalBornCamper

7
NOTA: Isso geralmente não funciona corretamente quando você inicia models.pye deseja migrar mais tarde. Nesse caso, você deve excluir suas migrações e seu banco de dados: / Ou resolver manualmente todos os erros em todos os arquivos de migração
— tuergeist

Melhor resposta ainda. Pode confirmar que ainda funciona em 2.1+
— Roys

1
Não vejo o problema apontado por @tuergeist no Django 3.0. Parece funcionar como um encanto
— caram

11

Na verdade, encontrei um tutorial para exatamente o que você está perguntando, você pode visualizá-lo aqui:

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

Um ponto-chave que provavelmente é relevante - você pode querer usar o campo db_table na classe Meta para apontar as classes realocadas de volta para sua própria tabela.

Posso confirmar que essa abordagem está funcionando no Django 1.3


Esse link dá um 404
— Bryan Oakley

1

Passos mais fáceis:

  1. Crie uma pasta de modelo em seu aplicativo (o nome da pasta deve ser o modelo )
  2. Exclua o arquivo model.py do diretório do aplicativo (faça backup do arquivo enquanto o exclui)
  3. E depois de criar o init arquivo .py na pasta do modelo
  4. E após o arquivo init .py em escrever uma linha simples
  5. E depois de criar o arquivo de modelo em sua pasta de modelo e o nome do arquivo de modelo deve ser igual ao nome da classe, se o nome da classe for 'Funcionário', então o nome do arquivo de modelo deve ser como 'funcionário.py'
  6. E depois no arquivo de modelo, defina sua tabela de banco de dados mesmo que escreva no arquivo model.py
  7. Salve isso

Meu código: from django_adminlte.models.employee import Employee

Para o seu: 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

2
Isso é exatamente o que ele está tentando consertar. Esta solução causará RuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.no django 2.x.
— radtek

0

Eu escrevi um script que pode ser útil.

github.com/victorqribeiro/splitDjangoModels

divide os modelos em arquivos individuais com nomenclatura e importação adequadas; ele também cria um arquivo init para que você possa importar todos os seus modelos de uma vez.

avise-me se isso ajudar

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.