models.py становится огромным, как лучше всего его разбить?

91

Указания моего руководителя: «Я не хочу помещать какую-либо логику в models.py. С этого момента давайте использовать это только как классы для доступа к базе данных, и сохраним всю логику во внешних классах, которые используют классы моделей или обертывают их».

Я чувствую, что это неправильный путь. Я считаю, что убирать логику из моделей только для того, чтобы файл был небольшим, - плохая идея. Если логика лучше всего подходит для модели, она действительно должна идти именно туда, независимо от размера файла.

Так есть ли простой способ просто использовать include? Говоря языком PHP, я хотел бы предложить супервизору, что у нас models.pyесть только include () классы моделей из других мест. Концептуально это позволило бы моделям иметь всю необходимую нам логику, но при этом уменьшать размер файла за счет увеличения количества файлов (что приводит к меньшему количеству проблем с контролем версий, таких как конфликты и т. Д.).

Итак, есть ли простой способ удалить классы моделей из файла models.py, но при этом модели работают со всеми инструментами Django? Или есть совершенно другое, но элегантное решение общей проблемы "большого" файла models.py? Любой вклад будет оценен.

Eddified
источник
7
Вы ведь знаете инструкцию импорта, верно?
balpha
7
PS. Я не имею в виду это оскорбительно, я просто хочу знать, где вы находитесь.
balpha
1
Да, но я не знал, будут ли инструменты администратора django работать, просто используя операторы импорта для извлечения моделей. Я бы предпочел спросить здесь, чем тратить много времени на попытки использовать простой импорт оле только для того, чтобы обнаружить, что инструменты django не работают с ними. Я признаю, что я новичок в python и django, поэтому я, вероятно, только понимаю простое понимание оператора импорта ...
Изменено

Ответы:

64

Django разработан, чтобы вы могли создавать множество небольших приложений вместо одного большого.

Внутри каждого большого приложения есть множество небольших приложений, которые пытаются быть бесплатными.

Если вы models.pyчувствуете себя большим, вы делаете слишком много. Стоп. Расслабьтесь. Разложить.

Найдите более мелкие, потенциально пригодные для повторного использования небольшие компоненты или части приложения. На самом деле вам не нужно использовать их повторно. Подумайте о них как о потенциально многоразовых.

Обдумайте свои пути обновления и разложите приложения, которые вы, возможно, захотите когда-нибудь заменить. На самом деле вам не нужно заменять их, но вы можете рассматривать их как отдельный «модуль» программирования, который в будущем может быть заменен чем-то более крутым.

У нас около десятка приложений, каждое model.pyне более 400 строк кода. Все они сосредоточены на менее чем полдюжине определений дискретных классов. (Это не жесткие ограничения, это наблюдения за нашим кодом.)

Разлагаемся рано и часто.

С.Лотт
источник
1
прямо в точку. любое нетривиальное веб-приложение было бы несколькими небольшими «приложениями». намек на contrib и другие популярные приложения, аутентификация пользователей - это одно приложение, теги - другое, профили пользователей еще одно и т. д.
Хавьер
4
Хотя это «правильный» способ и полезно знать, это не совсем то, что я искал. Прошу прощения, если не было возможности узнать, какой ответ я искал. :)
Изменено
@Eddified: если вы этого не сделаете, будет только хуже. Начни разделять сейчас.
S.Lott
Как ни странно, в этот самый момент я слушаю Джейкоба Каплана Мосса (Jacob Kaplan Moss) (из OSCON), который объясняет именно это в больших и строго обоснованных деталях ;-).
Alex Martelli
13
Ответ Гленна Мейнарда на этот раз намного лучше. Разделение сложного веб-приложения на множество приложений, безусловно, является хорошей практикой, но также можно провести рефакторинг файла model.py ВНУТРИ приложения. Эти два действия могут быть ортогональными.
Эрик
108

Для классов модели естественно содержать методы для работы с моделью. Если у меня есть модель Book с методом book.get_noun_count(), это то, чему она принадлежит - я не хочу писать " get_noun_count(book)", если только метод действительно не принадлежит какому-то другому пакету. (Может - например, если у меня есть пакет для доступа к API Amazon с " get_amazon_product_id(book)".)

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

site/models/__init__.py
site/models/book.py

__init__.py похоже:

from .book import Book

так что я все еще могу написать "from site.models import Book".


Следующее требуется только для версий до Django 1.7, см. Https://code.djangoproject.com/ticket/3591

Единственная уловка заключается в том, что вам нужно явно установить приложение каждой модели из-за ошибки в Django: он предполагает, что имя приложения является предпоследней записью в пути к модели. "site.models.Book" дает "сайт", что правильно; "site.models.book.Book" заставляет его думать, что название приложения - "модели". Это довольно неприятный прием со стороны Django; вероятно, ему следует поискать совпадение по префиксу в списке установленных приложений.

class Book(models.Model):
    class Meta: app_label = "site"

Вы, вероятно, могли бы использовать базовый класс или метакласс, чтобы обобщить это, но я пока не озаботился этим.

Гленн Мейнард
источник
2
+1 Я успешно этим воспользовался. Хотя С. Лотт прав в том, что несколько приложений - это хорошая идея, это решение здесь и сейчас.
Александр Юнгберг
35
Я не вижу особой пользы от разделения вещей на группы приложений, когда ваши модели тесно и внутренне связаны.
Glenn Maynard
2
Это меня интересует. Я прочитал опубликованную scompt ссылку django wiki и обнаружил следующее: «Было проверено, что это работает без мета-класса app_labels в текущей основной ветке». Значит ли это, что если вы работаете с основной веткой, мы можем отказаться от материала Meta: app_label? Это сбивает с толку, так как это после комментария о тикете, чтобы решить эту проблему.
Dan.StackOverflow
2
Я только что тестировал с транком (по состоянию на сегодня, r11286); если app_name не задано, модель просто не отображается в «sqlall appname» и, вероятно, не будет создана с помощью syncdb (но я не использую ее, поэтому я не могу ее протестировать). Это довольно запутанный случай ошибки, потому что он не вызывает никаких ошибок; он просто молча не появляется.
Glenn Maynard
2
Вау, прошло почти 10 лет, и мне все еще нравится это решение. Согласился, что это намного лучший подход, чем разделение кода на более мелкие приложения, что, на мой взгляд, может привести к созданию базы кода, о которой трудно рассуждать.
Майкл Хейс
5

Я не могу понять, какая из многих возможных проблем может быть у вас. Вот несколько вариантов с ответами:

  • несколько моделей в одном файле

    Поместите их в отдельные файлы. Если есть зависимости, используйте импорт для получения дополнительных моделей.

  • посторонняя логика / служебные функции в models.py

    Поместите дополнительную логику в отдельные файлы.

  • статические методы для выбора некоторых экземпляров модели из базы данных

    Создайте нового менеджера в отдельном файле.

  • методы, очевидно связанные с моделью

    save, __unicode__ и get_absolute_url являются примерами.

коричнево-коричневый
источник