Розділіть 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"

Отже, чи слід мені запускати alter для посилань вручну? це може принести мені проблеми з півднем?


Що відбувається в моделі 3, якщо ви спробуєте from app1.models.model1 import Store?
James Khoury

Також ви можете перевірити stackoverflow.com/questions/5534206/…
James Khoury

Відповіді:


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-графік для прикладу проекту, який робить саме це. 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 приблизно тиждень, тому мені цікаво, чи дозволяє найновіша версія це робити?
Vic

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
На випадок, якщо хтось задається питанням, чи все ще оновлений
NaturalBornCamper

6
ПРИМІТКА. Зазвичай це не працює належним чином, коли ви розпочали models.pyта хочете перенести пізніше. У такому випадку вам доведеться видалити свої міграції та базу даних: / Або вручну вирішити всі помилки у всіх файлах міграції
tuergeist

Найкраща відповідь все-таки. Може підтвердити, що це все ще працює у
Ройс,

Я не бачу проблеми, на яку вказав @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. А після створення файлу моделі у вашій папці моделі і ім'я файлу моделі має бути таким самим, як ім'я класу, якщо ім'я класу "Працівник", ніж ім'я файлу моделі має бути таким як "worker.py"
  6. А після у файлі моделі визначте таблицю бази даних так само, як і писати, як у файлі model.py
  7. Збережи це

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

Для вашого: від app_name .models. model_file_name_only імпортувати 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

він розділяє моделі на окремі файли з правильним іменуванням та імпортом; він також створює файл init, щоб ви могли імпортувати всі ваші моделі одночасно.

дайте мені знати, якщо це допомагає

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.