Разделить models.py на несколько файлов

89

Я пытаюсь разбить models.pyсвое приложение на несколько файлов:

Мое первое предположение было сделать это:

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

Это не работает, потом я нашел это , но в этом решении у меня все еще проблема, когда я бегу, python manage.py sqlall app1я получаю что-то вроде:

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;

Я не совсем уверен в этом, но меня беспокоит часть The following references should be added but depend on non-existent tables:

Это мой файл model1.py:

from django.db import models

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

Это мой файл 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"

И, по-видимому, работает, но я получил комментарий, alter tableи если я попробую это, произойдет то же самое:

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

Итак, следует ли мне запускать альтер для ссылок вручную? это может доставить мне проблемы с югом?

Diegueus9
источник
Что произойдет в модели 3, если вы попробуете from app1.models.model1 import Store?
Джеймс Хури
Также вы можете проверить stackoverflow.com/questions/5534206/…
Джеймс Хури,

Ответы:

33

Я бы сделал следующее:

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

затем

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

Но, если у вас нет веской причины, поместите model1 и model2 непосредственно в app1 / models.py, а model3 и model4 в app2 / models.py.

---вторая часть---

Это файл app1 / submodels / model1.py:

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

Таким образом исправьте ваш файл 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"

Отредактировано, на случай, если это снова у кого-то возникнет: ознакомьтесь с django-schedule для примера проекта, который делает именно это. https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/

Тед
источник
1
Что касается этого ответа, у меня возникла еще одна проблема, когда в models2.py сделайте что-то вроде from product.models import Product: ImportError: нет модуля с именем models
diegueus9,
68
вы бы сделали это таким образом, чтобы поддерживать один класс для каждого файла.
worc
50
«Почему» - это желание уменьшить размер массивного models.pyфайла. Я недавно сделал это, когда мой код вырос до более 15 тысяч строк. Хотя отличная рецензия. Процесс довольно простой. Главное предостережение в том, что вы должны не забыть определить явную app_label, поскольку Django по умолчанию извлекает ее из непосредственного модуля.
Cerin
1
Попробуйте это в 2016 году. Вторая часть поста все еще нужна? Я только перенес классы в отдельные файлы, написал свои, __init__.pyи вроде все работает нормально. Мне не пришлось исправлять файлы моей модели. Я могу получать и создавать объекты из оболочки и администратора django. Я пробовал django около недели, поэтому мне интересно, позволяет ли это теперь самая новая версия?
Вик
3
@Vic: app_label в классе Meta больше не нужен в новых версиях Django. См. Code.djangoproject.com/wiki/CookBookSplitModelsToFiles
jrial
147

Для всех, кто использует Django 1.9, теперь он поддерживается фреймворком без определения метаданных класса.

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

ПРИМЕЧАНИЕ. Для Django 2 все то же самое.

Команда manage.py startappсоздает структуру приложения, которая включает файл models.py. Если у вас много моделей, может быть полезно сгруппировать их в отдельные файлы.

Для этого создайте пакет моделей. Удалите models.py и создайте myapp/models/каталог с __init__.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

Вам нужно только сделать

#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

Примечание против импорта всех классов:

Явный импорт каждой модели вместо использования from .models import *имеет преимущества в том, что он не загромождает пространство имен, делает код более читабельным и сохраняет полезность инструментов анализа кода.

Вик
источник
5
На случай, если кому-то интересно, обновлен ли он до Django 2.0 docs.djangoproject.com/en/2.0/topics/db/models/…
NaturalBornCamper
6
ПРИМЕЧАНИЕ. Обычно это не работает должным образом, если вы начали models.pyи хотите выполнить миграцию позже. В этом случае вам нужно удалить свои миграции и свою базу данных: / Или вручную устранить все ошибки во всех файлах миграции
tuergeist
Еще лучший ответ. Могу подтвердить, что это все еще работает в 2.1+
Ройс
Я не вижу проблемы, указанной @tuergeist в Django 3.0. Кажется, работает как шарм
caram
11

Я действительно наткнулся на учебник именно по тому, о чем вы спрашиваете, вы можете просмотреть его здесь:

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

Один ключевой момент, который, вероятно, имеет значение - вы можете использовать поле db_table в классе Meta, чтобы указать перемещенным классам обратно в их собственную таблицу.

Я могу подтвердить, что этот подход работает в Django 1.3.

Адам Лученброерс
источник
Эта ссылка дает 404
Брайан Окли
1

Самые простые шаги:

  1. Создайте папку модели в своем приложении (имя папки должно быть моделью )
  2. Удалите файл model.py из каталога приложения ( пока вы его удаляете)
  3. И после создания файла init .py в папке модели
  4. И после инициализации файла .py напишите простую одну строку
  5. И после создания файла модели в папке модели и имя файла модели должно быть таким же, как имя класса, если имя класса - «Сотрудник», то имя файла модели должно быть похоже на «employee.py».
  6. И после того, как в файле модели определите свою таблицу базы данных так же, как напишите, как в model.py файле
  7. Сохрани это

Мой код: from django_adminlte.models.employee import Employee

Для вашего: из 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
Это именно то, что он пытается исправить. Это решение вызоветRuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS. в django 2.x.
radtek
0

Я написал сценарий, который может пригодиться.

github.com/victorqribeiro/splitDjangoModels

он разбивает модели на отдельные файлы с правильным наименованием и импортом; он также создает файл инициализации, чтобы вы могли импортировать все свои модели сразу.

Позвольте мне знать, если это помогает

user1659565
источник