Когда ваше джанговские приложение/проект обрастает кодом всё больше и больше, то встает вопрос как максимально удобно организовать файловую структуру. И хотя Джанга не сильно капризна и требовательна к структуре модулей/пакетов, но всё-таки не всегда разработчик может себе позволить вольности. Джанга всё-таки ожидает, что какие-то части приложения будут лежать в определенных местах. Это относится к моделям, тестам, шаблонным тегам, определениям админки и т.п.
Из-за этого кстати и разработчик сторонних приложений ожидают, что ваш проект будет выглядеть так, а не иначе, поэтому каким-то образом на это закладываются.
Но поскольку мы имеем дело с очень гибким инструментов в лице питона и Джанги, то можем в большинстве ситуаций позволить себе обойти эти ограничения.
models.py
Наверно самая частая проблема - это разделение слишком большого файла models.py на более мелкие, атомарные, отвечающий за одну модель модули. Об этом не редко спрашивают в различных форумах и рассылках.
На самом деле, задача эта не сложная, но при решении надо не забыть одну хитрость, чтобы всё заработало как надо.
Итак представим, что у вас есть большой и толстый файл models.py, в котором есть несколько моделей. Для примера возьмем предметную область блога - модели Post, Comment, Tag. Мы хотим чтобы каждая модель обитала в своем модуле, но при этом, чтобы обычные джанговские инструменты продолжали работать как обычно и даже не подозревали о таком разделении.
Создаем вместо модуля models.py пакет models c такими файлами:
- models/
- __init__.py
- comment.py
- post.py
- tag.py
В модули с соответствующими названиями, помещаем определения моделей. При этом для модели Comment имеющей ссылку на Post надо не забыть импортировать этот самый Post:
from blog.models.post import Post
Ну а для того чтобы посты можно было связать с тегами:
from blog.models.tag import Tag
Следующим шагом является импортирование всех трех моделей в __init__.py модуле пакета:
from blog.models.comment import Comment
from blog.models.post import Post
from blog.models.tag import Tag
Это делается для того, чтобы внешний код мог привычно импортировать модели из приложения и не думал о том, где они там на самом деле лежат. Например во views.py пишем:
from blog.models import Post, Comment, Tag
и работать с моделями как будто они лежать в привычном models.py.
Но вот именно с этими изменениями не всё заработает как надо. Например syncdb не создаст таблички для расположенных таким образом моделей. Причина в том, что джанга при своей "загрузке" пробегается по INSTALLED_APPS и кеширует модели, привязывая их к каждому из приложений. Причем названия этих приложений определятся просто - имя родительского пакета модуля, где лежит модель. В нашем "разделенном" варианте это models. В обычной ситуации это было бы blog и модели бы прицепились к правильному приложению. Для исправления этого недоразумения, необходимо воспользоваться возможностью явно для модели указать приложения к которому она относится:
class Post(models.Model):
#...
class Meta:
app_label = 'blog'
и так же для моделей Comment и Tag.
Теперь всё, модели расположены по собственным файлам, разработчику проще с ними оперировать и при этом вся остальная Джанга работает как обычно, не замечая подвоха.
tests.py
Подход описанный выше для models.py справедлив и для разделения тестов на модули и создания пакета tests. Последовательность такая же:
- сделать пакет
tests - создать необходимые модули внутри него
- разбросать тест кейсы по модулям
- в
__init__.pyимпортировать все тест кейсы из дочерних модулей. Обычно я не заморачиваюсь и пишу... import *
Кстати, очень часто для тестов нужны какие-то тестовые модели, которые в самом приложении не используются. Эти модели можно свободно объявлять в недрах tests.py/tests, прописывая им правильный app_label.
И ещё, если вы используете doctests, то с их разделение на какие-то логические части гораздо более трудоемкая задача, о который сейчас я говорить не буду, поскольку сам ещё не выработал best-practies.
admin.py
С определением админки всё достаточно просто. Если вы используете admin.autodiscover(), который пробегаясь по INSTALLED_APPS подгружает модуль admin в каждом из приложений, то можете в admin.py импортировать любый модули в которых тоже может быть определена админка. И тогда все определения во внешних модулях тоже зарегистрируются в админке.
В следующий раз расскажу, как можно держать шаблонные теги не только в templatetags пакете.
Но учтите, что вы должны быть точно уверены, что хотите раздробить какие-то модули. Иначе вы просто потеряете время и при этом усложните код проекта для понимания людей со стороны и даже вам самим в будущем.
Разделяйте и властвуйте!:-)
Комментарии 12
спасибо, полезно.
Оставлен 21 Апрель 2009 в 09:41 ¶Алекс, почему импорты в
Оставлен 21 Апрель 2009 в 13:27 ¶__init__.pyабсолютные?Я рискну высказать жесткую и непопулярную точку зрения (впрочем, это для меня обычно :-) ). Так вот, эта "проблема" на самом деле исключительно в голове. Я не видел ни одного реального юзкейса, когда бы работать с models.py становилось удобнее от разделения. Связанные по смыслу модели удобно хранить вместе.
А вот если они не связаны (или слабо связаны) по смыслу, то надо разделять приложение на несколько, а не заниматься противоестественными вивисекциями на сердце внутри одного Франкенштенйа.
Оставлен 21 Апрель 2009 в 14:25 ¶Моя привычка всегда писать абсолютные пути. В данном случае можно и относительные использовать, но тогда надо следить, чтобы в других местах эти модули так же импортировались.
Оставлен 21 Апрель 2009 в 19:45 ¶На то все люди и разные, что головы у них работают индивидуально. И в некоторых ситуациях, может быть действительно кому-то проще разбросать классы по разным модулям. В конце концов такой принцип применяется в одном очень популярном ОО языке.
Согласен, но зачастую к появлению Франкенштейна приводит слишком большое рвение делить функционал на приложения. Тут баланс нужен.
Оставлен 21 Апрель 2009 в 20:37 ¶templatetags?
Необходимость разделения, действительно, весьма субъективна, врядли когда-нибудь удастся выработать жесткие правила, для подобных вещей, когда и что делать. Десяток моделей вполне замечательно могут уживаться в одном модуле, а какие-то три - никак, тем не менее (допустим) они остаются мелкими и не хочется связываться с лишними сложностями при их разделении.
..bw
Оставлен 22 Апрель 2009 в 08:03 ¶Нет, я о другом удобстве. Это не субъективная вещь типа "мне кроссовки Адидас кажутся удобнее Рибок", а вполне объективная: система с большим количеством компонентов и уровней абстракции -- сложнее. Или по-другому, головы у всех работают по-разному, но у многих они работают просто неверно (даже у большинства, иначе бы не было нужды в обучении).
Так вот я утверждаю, что дополнительный уровень абстракции на уровне моделей (а именно этим и является разделение их на файлы) практически всегда является лишним. И по идее, это очень понятная вещь, потому что в MVC-приложении модель как раз и задает собственно предметную область (точнее, ее описывает), а значит до некоторой степени и определяет, о чем вообще приложение, что оно должно делать.
Если в голове появляется нужда разделить модели, то скорее всего это должно вести к разделению приложений. Либо она просто появляется от желания спроектировать "что-нибудь эдакое", и тогда это желание надо задушить :-)
Я верю, что бывают случаи, когда ситуация одного приложения с несколькими моделями все таки нужна: мир богат. Но я ни разу с таким не встречался.
Оставлен 22 Апрель 2009 в 10:28 ¶Да, на всякий случай хочу сказать, что когда говорю про "многих", у которых голова неверно работает, я не имею в виду каких-то конкретных людей. Только конкретную ситуацию.
Оставлен 22 Апрель 2009 в 11:12 ¶Я помню, мы когда-то в одном проекте выносили какую-то очень специфичную модель из общего файла - просто положили рядом с models.py отдельный файл и в models.py он импортировался. Ничего более сложного пока не возникало в практике :)
Оставлен 23 Апрель 2009 в 18:13 ¶Ну так о том и речь, но когда такая ситуация возникла - вот, пожалуйста, красивое решение
Оставлен 24 Апрель 2009 в 18:27 ¶Прикол! Сегодня обнаружил у себя в ленте пост: http://justinlilly.com/blog/2009/oct/27/fix-your-models-subdir/. Вспомнил про Ваш пост. Что об этом думаете?
Оставлен 05 Ноябрь 2009 в 13:58 ¶Да, это обратная сторона медали. У каждого решения есть свои особенности. Ждем когда тикет Майка Мэлоуна закроют.
Оставлен 06 Ноябрь 2009 в 10:25 ¶Пингбеки 2
как разбить models.py на несколько файлов - см. http://webnewage.org/2009/04/21/split/ и http://webnewage.org/2009/04/24/smart-split/
http://webnewage.org/2009/04/21/split/
Оставьте комментарий