About Blog Dev | Alfa Romeo SZ Conkeror wishlist

Расположение файлов в проектах Django

Последнее время мне всё более и более странным (я бы даже сказал “недальновидным”) кажется решение авторов оригинального туториала по Джанге показывать именно такой формат расположения файлов в джанге (и уж тем более то, какой sys.path они там используют): в туториале все файлики, созданные с помощью startproject, лежат в одной директории вместе с приложениями. Соответственно, все импорты выглядят как from someproject.someapp import views.

Мне понятно, откуда ноги растут — на деле у них все приложения лежат в sys.path, и потому импортируют они оттуда как from someapp import views, а проект — это лишь настройки да корневой конфиг урлов. Тогда можно родительскую для всех проектов директорию положить в sys.path, и менять только DJANGO_SETTINGS_MODULE. Но в любом случае одним интерпретатором питона для двух джанговских проектов не обойдёшься (спасибо этому самому DJANGO_SETTINGS_MODULE), а способность к лёгкому созданию дистрибутива и его распространению страдает порядочно (что особенно важно для опенсорсовых проектов).

Поэтому мне значительно больше нравится другой подход к делу, который я применяю во всех своих проектах, в том числе и в Byteflow:

project/
  apps/        # собственно приложения
  template/    # шаблоны
  static/      # статические файлы — картинки оформления, стили, JS
  media/       # файлики, загруженные пользователями, не версионируется
  locale/      # переводы
  compat/      # тут библиотеки типа django-atom
  manage.py    # файлы, относящиеся к описанию проекта
  settings.py
  urls.py
  ...

При этом в sys.path добавляется сама директория проекта, DJANGO_SETTINGS_MODULE становится равен settings, а в settings.py двумя строками кода в sys.path добавляется и apps/ с compat/1. В результате все импорты простые и не содержат имени проекта (что тупо хотя бы потому, что я не могу склонировать проект рядом и поэкспериментировать в нём из-за того, что будут проблемы с импортами), а проект становится достаточно независимой вещью, которая для разворачивания на каком-то сервере требует только Джангу и библиотеки, которые достаточно распространённые и/или большие для того, чтобы не включать их в проект.

1

Как это делается, можно увидеть в settings.py у Byteflow.

Add post to: Delicious Reddit Slashdot Digg Technorati Google
Comment

Comments

dobrych 30.06.2008 19:44

Здравствуй рельсы и пилоны :-)

А еще бы джангу прямо в проект фризить, нужной версии прямо из репозитория, и плагины внешние. Полный контриб всегда на месте. А еще… ой ладно, хватит :-)

reply
Александр Соловьёв 30.06.2008 20:07

Нууу… В майдеко-то было точно так же. А что конкретно в лейауте не нравится-то?

reply
Сергей Кириллов 30.06.2008 20:15

Прикольно, у нас похожий лайаут, только весь код в src, и locales не вынесены на верх. Зато в каждом проекте своя зафризиная версия джанги ;)

reply
Александр Соловьёв 30.06.2008 20:53

Зато в каждом проекте своя зафризиная версия джанги ;)

Я стараюсь держать все проекты на последней версии транка, ну и плюс меркуриал не умеет (прямо) такого, как svn:externals.

reply
Alexander Artemenko 30.06.2008 22:34

Кстати, а git вроде умеет, но я пока только читал, сам не пробовал. Говорят, git-remote помогает. Но это, разумеется только в том случае, если все репозитории на git, что маловероятно.

reply
Александр Соловьёв 30.06.2008 22:56

Ну, с меркуриалом тоже можно такое учудить, используя forest, но опять же, если все репозитории — меркуриал. Плюс для меня совсем не очевидно, зачем это надо. :)

reply
Сергей Кириллов 30.06.2008 23:07

У нас всё в лоб. Просто в меркуриале лежит svn. Заходишь туда, и: svn up, hg addremove, hg ci -m “Django update”

reply
Александр Соловьёв 30.06.2008 23:11

Хех, хардкор. :) Не, я всё-таки предпочитаю джангу как-то отдельно апдейтить, уж очень она большая…

reply
Сергей Кириллов 30.06.2008 23:16

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

А, не. Есть один. hg churn показывает что 95% изменений всего проекта я накоммитил ;)

reply
Alexander Artemenko 30.06.2008 23:35

Потому что надо апдейтить django в отдельной рабочей копии и из под другого пользователя. Какого-нибудь svn-updater.

reply
Александр Соловьёв 30.06.2008 23:57

Ну с автором решить просто — hg ci -u svn-updater, и дело в шляпе. ;)

А на тему слетания… Ну да, но меня пока это не преследует, а там и релиз не за горами. :) Но твои проблемы я хорошо понимаю, просто у меня количество проектов небольшое.

reply
Сергей Кириллов 1.07.2008 0:32

Да понятно, но это же и не проблема вовсе. Я churn этот раза три в жизни запускал. Вспомнилось просто.

reply
Vadim Fint 1.07.2008 18:42

Кстати да.

Мы правда джангу в отдельном бранче держим (базаровцы.. хотя у вас тоже самое можно делать =)). Соответственно цикл примерно такой:

/trunk /django

  1. апдейтим джангу

    • cd /django
    • svn up
  2. коммит

    • bzr ci -m “Updated django r1234 -> r1321
  3. экспорт

    • cd ../trunk/pylib/
    • rm -rf django # убрали старое
    • svn export ../../django/django/django django # ой мля +)
  4. мержим то что только что сэкспортнули

    • bzr merge-into ../../django .
    • bzr ci -m “Merged django from source:/django/django/django@django,123.”

Все такие пляски с бубнами, потому что бранч джанги:

django/
  django/
  patches/ # <<< ~20 патчей за которыми другим способом следить ну никак не получится

А так.. коммиты в транке простенькие, можно откатится куда угодно, и тысячи .svn/ не мешаются в транке.

reply
Хрюндель 30.06.2008 21:08

В принципе нормальный такой лэйаут.. Только как ты static media делишь то? Или я туплю или ты дэвид блэйн.. MEDIA_ROOT ведь вроде один и все линки с get_something_url аппендятся к нему.. Как ты смог разделить их?

reply
Александр Соловьёв 30.06.2008 22:19

Посмотреть в код тебе религия помешала? ;) MEDIA_ROOT и MEDIA_URL так и направлены в media/, чтоб джанговские хендлеры не ломались, а для static/ я специально завёл STATIC_ROOT и STATIC_URL, которые контекстным процессором отправляются в темплейты.

reply
Хрюндель 1.07.2008 6:22

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

reply
Александр Соловьёв 1.07.2008 9:12

Ну, я написал, как я сделал. Кому будет интересно — прочтёт комментарий, не так много инфы, чтобы в отдельный пост это писать.

reply
Alexander Artemenko 30.06.2008 22:38

Эх, надо будет у себя все переколбасить. Но это после отпуска. Сейчас уже ни о чем не хочется думать :)

Кстати, когда уже для django будет нормальный инсталятор? Я имею ввиду такой, чтобы, скажем, имея на сервере django определенной версии в python пути, достаточно было распаковать где-то исходники движка, открыть определенный URL и настроить все через веб.

reply
Александр Соловьёв 30.06.2008 22:57

настроить все через веб.

Мечты-мечты… :D Да, деплой было бы неплохо как-то заапгрейдить, а то сейчас это всё может быть достаточно муторно. :)

reply
Vadim Fint 1.07.2008 18:32

Хм.. дефолтовый джанговский лэйаут явно для не очень крупных проектов придуман. А тем кому надо — сами и меняют.

Вообще ваш подход сразу противоречит большинству других. То есть если взять byteflow и поставить его грамотно system-wide, то будет небольшая попа в виде “черт возьми, всё в pythonpath?!”. Темплейты — пофик, их хоть через pkg_resources грамотно вытаскивать можно. Но вот статику.. =)

src/
  bin/
    manage.py
    retranslate.py
  pylib/
    my-super-project/
      toolset/
      another-non-web-library/
      locale/        # << whole project (for executable scripts, etc.) locale files
      web/
        templates/   # << base templates
        locale/      # << base translations
        django_app1/
          templates/ # << django_app1 templates
          locale/    # << django_app1 locales
        django_app2/
        ...
        settings.py
    django/
    override-library-1/
    override-library-2
    ...
  share/
    media/
      js/
      css/
      blabla/
    docs/
  setup.py

Вот мой вариант. Соответственно, в pythonpath у нас самое естественное — pylib (при system-wide установке — станет site-packages).

Но это — минижопа для сторонних приложений. Во-первых, многие:

  1. там где settings.py — там project dir — значит там все папки - приложения
  2. os.path.dirname(app_mod.__file__) — там project dir (грешат всякие тулзы типа deseb, evolvedb)
  3. ещё у многих сносит крышу от полного питоновского пути к приложению: my-super-project.web.app1 — многие отрезают начало, и пытаются импортить найденное напрямую (т.е. вместо полного пути — импортят web.app1, что неверно, конечно).

Ну и ещё так, по мелочи… Но это всё чинится на раз-два =).

p.s. я специально пытался не колдовать с sys.path p.p.s. а проблема импорта с именем… ээээ… from .. import ? p.p.p.s а проблема “склонировать”… мм. Поменять 1 PYTHONPATH в консоли — и будет клон. Или я не понял в чем проблема?

reply
Александр Соловьёв 1.07.2008 18:59

То есть если взять byteflow и поставить его грамотно system-wide, то будет небольшая попа в виде “черт возьми, всё в pythonpath?!”.

Ога, я об этом как-то не задумывался, потому что sys.path для всех джанговских проектов своих всегда дорисовываю в VirtualHost’ах у апача. Надо будет поразмышлять…

p.p.p.s а проблема “склонировать”… мм. Поменять 1 PYTHONPATH в консоли — и будет клон. Или я не понял в чем проблема?

В том, что люди показывают свои приложения, где имя самой верхней директории — важно в коде питона. А это не очень клёво. :)

Вообще было бы неплохо придумать какой-то универсальный лейаут, который бы все использовали. У тебя он слегонца развесистый выходит, на самом-то деле. :)

Ещё один момент — не люблю файлы темплейтов рядом с питоновскими, правда сейчас задумался — как-то это иррационально, ведь поиск по файлам можно ограничивать типом файла… Но пока всё ещё не люблю. :)

reply
Vadim Fint 1.07.2008 20:05

ура! я думал сейчас как наорёшь и снова я обижусь =)

Вообще было бы неплохо придумать какой-то универсальный лейаут, который бы все использовали. У тебя он слегонца развесистый выходит, на самом-то деле. :)

ну.. я его показал для своего текущего весьма увесистого, но к сожалению закрытого (показать не могу), проекта. =) А так — если например не использовать локали внутри приложений — у меня автоматом это из общих локалей браться будет. Если не использовать тонну своих библиотек — то и лишнего в /pylib/ не будет. По крайней мере цель у меня была следующего характера: надо было чтобы билд не сильно отличался от исходников.. ведь все же питон язык интерпретируемый и перемешивать все файлы после изменения каждой строчки — бее.. А билдить в реалтайме все равно нужно — ибо у меня тут и си и ситон с пурексом.. Главное делать так чтобы сам по себе проект от лейаута не сильно зависил =)) Т.е. если вдруг будет идея что-то сделать по-другому — чтобы это не было мегасложно. Посему и абсолютные импорты с именем проекта в начале — нафик нафик. Хотя grep и сколько-то часов (но не дней) для довольно крупного проекта, при налиичии регрессивных тестов — ничтожная цена.

Ещё один момент — не люблю файлы темплейтов рядом с питоновскими, правда сейчас задумался — как-то это иррационально, ведь поиск по файлам можно ограничивать типом файла… Но пока всё ещё не люблю. :)

я вот кстати тоже с этим долго дрался. Все мне хотелось темплейты куда-нибудь выкинуть подальше. А дрался с setuptools и distutils. Я уже не помню все грабли на которые пришлось наступить, но точно знаю что теперь я темплейты не считаю таким уж “статическим” дерьмом без которого всё работать может =)))). На самом деле если пытаться делать приложения “detachable” как плагины — то при большом их количестве или старте нового проекта становится комфортнее (:

Так или иначе дело не только в темплейтах — ибо джанговские приложения ведь не только их использовать могут.. логично что то, к чему больше никто не захочет получать доступ (в отличие от графики, скажем, куда неплохо бы статик-сервер отправить) держать в самом ”сердце”.

reply
Александр Соловьёв 1.07.2008 21:09

ура! я думал сейчас как наорёшь и снова я обижусь =)

Лол. :D В тот раз весело поговорили, да… :)

Посему и абсолютные импорты с именем проекта в начале — нафик нафик.

Их в любом случае надо нафиг, потому что оччень мешает. :-)

На самом деле если пытаться делать приложения “detachable” как плагины — то при большом их количестве или старте нового проекта становится комфортнее (:

Я так и стараюсь, но темплейты всё равно выношу отдельно. Хотя бы потому, что я стараюсь их как-то структурировать директориями по приложениям, т.е. рендерить в “blog/post_list.html”, а не просто в “post_list.html”, и если ложить их в директории приложения, выходит “application/templates/application/some_template.html”. Это разит мою нежную душу прямо до скрипа, какая-то прямо противоестественная вложенность. :)

Статику само собой надо отделять, я думаю это и понятно, да и сделать иначе сложно. А вот для темплейтов всё как-то прямо так… Почему бы не добавлять имя приложения как директорию, если шаблоны лежат в приложении? Очень бы удобно было, имхо. И логично.

reply
Vadim Fint 1.07.2008 22:36

Почему бы не добавлять имя приложения как директорию, если шаблоны лежат в приложении? Очень бы удобно было, имхо. И логично.

потому что например я пока не придумал способ в темплейт лоадере определять в каком приложении темплейт вызывается. Думал я, правда, не долго и немного над другой задачей — я хотел чтобы если запрашивается в приложении blabla темплейт index.html — то он чтобы сначала искал именно в темплейтах текущего приложения, а потом пропускал через другие темплейт-лоадеры. Но чтобы даже не пытался искать темплейты у других приложений.

Собственно, реализовывать это я буду 100%, ибо нам очень надо. Потом поделюсь (:

reply
Vadim Fint 1.07.2008 22:38

чтобы былопонятнее

templates/
  index.html
blabla/
  models.py
  templates/
    index.html
blabla2
  models.py
  templates/
    index.html

надо чтобы если в blabla2 запрашивается index.html — чтобы он сначала искал его в blabla2/templates/index.html, а уж если не найдёт — то в templates/ общих. В текущей реализации джанги если стоит лоадер app_directories — то blabla/templates будет ваще выше в списке чем blabla2/templates — тем самым index.html возьмётся оттуда.

Иными словами — в джанге и так сейчас все делают мини-абсурд вида blabla2/templates/blabla2/index.html :) Так что по-другому и не выйдет.

reply
Александр Соловьёв 2.07.2008 16:08

Да, я понял как. Я наверное сам пороюсь, на тему осуществления своей идеи с загрузчиком.

reply

Comment form for «Расположение файлов в проектах Django»

Required. 30 chars of fewer.

Required.