Наш опыт работы с Django, или 10 полезных модулей, облегчающих жизнь

    Бесценный опыт работы с Django, или Django для блондинок, брюнеток и всех-всех-всехПоследние 15 недель мы активно работали над проектом «Стиллион», первым нашим мейнстрим-проектом, написанным на Django. Был приобретен интересный опыт, которым мы хотели бы поделиться с сообществом.
    Статья, прежде всего, будет интересна новичкам в Django.


    Модули Django


    south

    South — механизм миграции схем и данных в БД для django, то, без чего жить невозможно при совместной разработке. К сожалению, в Джанге нет штатного механизма миграций для отслеживания изменений в схеме базы данных проекта. Для восполнения этого пробела мы использовали south, который показал себя с хорошей стороны, главное вникнуть в то как он работает, в документации всё отлично описано. Грабли: миграции можно накатывать без фикстур, этим надо пользоваться. Миграции данных надо писать руками. При использовании нештатных полей (например WYSIWYG-поле) и последующего отказа от них старые миграции не будут работать (но их можно переписать вручную).

    django-mptt

    Реализация nested sets для моделей django. Добавляет соответствующие поля, а также методы работы с деревом. Незаменимая штука для реализации иерархических структур в реляционной СУБД. Для представления деревьев в админке использовали fein-cms.
    django-mptt

    django-annoying

    Набор полезных утилит, таких как декораторы видов render_to и ajax_request или HttpResponseReload. Рекомендуем для повышения элегантности кода.

    django-debug-toolbar

    Модуль, отображающий панель с отладочной информацией. Нас прежде всего интересовал лог SQL-запросов, который дополнен информацией об источнике запроса, временем и т.п.

    pymorphy

    Морфологический анализатор, интегрируемый с Django. Используется для склонения слов, которые хранятся в нормальной форме (то есть избавляет нас от хранения различных форм одного слова). Ещё умеет ставить слова во множественное число:
    morph.pluralize_inflected_ru(u'ПОПУГАЙ', 38)
    >>> ПОПУГАЕВ
    Недостатки — медленный sqlite в качестве бекенда (есть более быстрые альтернативы Shelve, CDB и Tokyo Cabinet, но нам они не нравятся), не все слова корректно обрабатывает, но это бывает редко.

    pytils

    Чтобы не страдать от «18 март 2011» для работы с русскими датами мы используем pytils. Модуль, кстати, умеет транслитерировать русский текст и выбирать правильный падеж в зависимости от числа, как и pymorphy (правда, без словаря, придётся хранить в шаблоне 3 формы слова).

    sorl-thumbnail

    Приложение для автоматического создания миниатюр изображений. Работает на базе key-value хранилища (в качестве бекэнда использован, разумеется, доступный из коробки redis). В бэкенде хранятся не сами миниатюры (они хранятся в файлах), а всего лишь мета-информация (принципиальная схема работы модуля).
    {% thumbnail image "100x100" crop="top" as im %}
    <img src="{{ im.url }}">
    {% endthumbnail %}
    

    sorl-thumbnail

    django-compress

    Склейка и минификация CSS и JS. В конфиге хранятся наборы файлов для склейки, в шаблоне указываем название сборки и compress генерирует минифицированную версию (фильтры YUI и CSSMin). Можно расширять функциональность своими фильтрами. Поддерживает версионное название файлов, что очень удобно при выставлении заголовка Expires на долгое время вперёд (manage.py syncompress при выкладке на продакшен обновит названия и содержимое минифицированных файлов сам).

    django-sentry

    Очень полезное приложение от создателей DISQUS, позволяющее удобно логировать ошибки в базу данных. Sentry перехватывает исключения (например, Http404), сохраняет их и предоставляет красивый интерфейс, в котором показана частота возникновения ошибки (в том числе графически). Возможен сбор ошибок с нескольких серверов. Обзор Sentry на Хабре
    django-sentry

    django-admin-tools

    Приложение помогает сделать дашборд админки полезным. Имеется встроенный набор виджетов, но не составит труда написать свои. Также можно сформировать меню под свои задачи, которое будет доступно на всех страницах админки. Обзор Admin Tools на Хабре
    django-admin-tools



    Комментарии


    Когда мы делали комментарии, решили, что оптимальным вариантом будет авторизация через сторонние сервисы (вконтакте, фейсбук, openid и иже с ними). Это очень удобно для пользователя, поскольку ему не нужно придумывать и помнить массу паролей от разных ресурсов. Для того, чтобы сделать это быстро и просто, есть сервис Loginza. Интерфейс нам не очень понравился и мы реализовали интеграцию с основными сервисами самостоятельно.

    Комментарии

    За основу был взят модуль publicauth, но его пришлось основательно допилить. Дело не ограничилось добавлением интеграции с мейл.ру и другими российскими сервисами. Мы добавили «правильную» проверку подписи провайдеров openId и сделали достаточно дружественный виджет в «два клика».



    Оптимизация призводительности


    На практике, одной из слабых сторон django оказался ORM. Он, как и все ORM, способствует порождению большого количества запросов и потребляет много памяти, когда извлекает данные. Без применения кеширования генерация главной страницы занимала несколько секунд. Из возможных стратегий оптимизации кеширование оказалось самым дешёвым и эффективным, так как схема БД не позволяла применять штатные средства, такие как select_related.

    Кэширование

    Кеширование блоков по таймауту, доступное «из коробки», нас не устраивало, так как не предусматривало удобного способа сбрасывать кеш. Поэтому была выбрана следющая стратегия: кеш живёт бесконечно долго (TIMEOUT=0), а одной из частей ключа записи в кэше является дата последнего обновления основного объекта. Зависимые объекты обновляют основной с помощью post_save сигналов. Таким образом при изменении объекта имя ключа для кэширования автоматически изменяется, что позволяет видеть на сайте самые актуальные данные. В качестве бэкенда кэша используется Redis с алгоритмом вытестения allkeys-lru (давно не использованные ключи кэша будут удалены при достижении ограничения maxmemory). В редисе, кстати, мы храним ещё и сессии пользователей, чтобы разгрузить бд ещё немного.

    Order by RAND()

    Чтобы не нагружать базу данных выборкой случайных значений через .order_by('?'), используется следующий подход: данные, которые необходимо перемешать, достаются и кладутся в кеш (особенно, если логика выборки этих данных не тривиальна и требует большого числа запросов) в виде списка идентификаторов, а при выдаче к этому списку применяется random.shuffle().
    Резюме: кешируйте с умом:-))


    В качестве заключения


    Django — отличный фреймворк с большим количеством неплохих дополнений; когда пользуешься им, понимаешь, что он был создан для нашего удобства. Приятного кодинга!
    ЗЫ. У вас есть знакомые верстальщики / фронтенд разработчики, ищущие работу (постоянная, в офисе, Москва)?
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 59

      +3
      я бы добавил к незаменимым вещам — werkzeug, без него как без рук при разработке.
        +1
        С нормальной IDE и дебаггером, можно и без него )
          +2
          Я всегда думал что werkzeug + jinja2 + sqlalchemy + wtforms вместо django, а не вместе.
          Что то упускаю?
            0
            В векрцойке есть экстеншн и менеджмент команда ./manage.py runserver_plus

            С ее помощью запускается дев сервер на базе веркцойка и в темплейт дебаге можно выполнить питон команду или посмотреть переменную поглубже.
            Мелочь, а приятно
              0
              > В векрцойке есть экстеншн и менеджмент команда ./manage.py runserver_plus

              Это не в веркцойге. Это аппликейшен для джанги, который юзает веркцойг.
            +5
            Маленький скрипт внизу, и вы можете запускать локально ваш проект на 8000 порту, например, и в случае ошибки — прямо в браузере смотреть переменные, запускать команды и т.п.

            #!/usr/bin/env python
            import os, sys
            from os.path import abspath, dirname
            from werkzeug import run_simple, DebuggedApplication
            from django.views import debug
            from django.core.handlers.wsgi import WSGIHandler

            def null_technical_500_response(request, exc_type, exc_value, tb):
            raise exc_type, exc_value, tb
            debug.technical_500_response = null_technical_500_response

            os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
            path = os.path.abspath(dirname(dirname(abspath(__file__))))
            sys.path.append(path)

            if __name__ == '__main__':
            run_simple('www.site.com', 8000, DebuggedApplication(WSGIHandler(), True), True)
              +1
              круто!
              +1
              Да werkzeug + jinja2 + sqlalchemy + wtforms = Flask
                +1
                спасибо, пригодится :)
              0
              так же к незаменимым стоит добавить django-templatetag-sugar, при установуке sentry он поставиться как зависимый
              0
              А почему твиттера нет в числе сервисов через которые можно залогиниться?
                0
                Пока нет (ориентировались на самые популярные для нашей аудитории), но скоро будет.
                +3
                Свой вариант реализации авторизации на GitHub-e выложите?

                P.S. Firefox и Chrome блокирует Vkontakte при авторизации
                  0
                  Пока для опенсорса слишком сыровато. Но планы выложить есть, да.
                    +4
                    Выкладывайте, допилим :-)
                    +1
                    Я тоже в свое время взял за основу publicauth и запилил свою реализацию: github.com/klen/django-netauth

                    Вот только до mail.ru руки не доходили, но пользовать можно вполне. Мб ребята кинут патч на openid.
                    +5
                    Совсем скоро выйдет django 1.3, там будет замечательный django.contrib.staticfiles. И вы, наверное, столкнетесь с проблемой, если захотите на него перейти, т.к. django-compress по-нормальному работать не будет больше, да и вроде никто его не поддерживает и не развивает уже долгое время. Поэтому лучше бы пораньше перейти на что-то другое (я бы выбирал между github.com/miracle2k/webassets и github.com/jezdez/django_compressor).
                      0
                      Мы уже используем 1.3RC в продакшене, правда пока без staticfiles. Обязательно пристально посмотрим на альтернативы compress, модуль django-compress действительно не развивается.
                        0
                        Большое спасибо за то, что показали webassets. Используем django_compressor, но в нем не хватает management command. WebAssets в свою очередь похоже включает все лучшее из compressor'а и compress'а.
                        0
                        Взял пару модулей на заметку. Спасибо :)
                          –1
                          Я сессии целиком храню в cookie. Если сессия небольшая (чаще всего так и есть), то она без проблем помещается в cookie, при этом не создает никакой нагрузки на базу, ни единого запроса. Точно так же поступил с сообщениями (теми, что messages.add_message).
                            +1
                            За что минусы? Можно в двух словах написать, в чем моя глобальная ошибка?

                            Сессии в куках храню не только я, куки, естественно, зашифрованные и подписанные. Что в этом криминального?
                              0
                              Как вариант — расшифровка/зашифровка, проверка аутентичности и валидация могут создавать большую нагрузку, чем обращение к БД и, тем более, к кэшу в ОЗУ. Плюс традиционное недоверие к данным, поступающим от пользователя.
                                0
                                Ну, я не верю, что roundtrip к базе данных может быть быстрее, чем расшифровка/зашифровка. Бенчмарков не проводил, но просто не верится, что это может быть. Тем более, что у меня база на отдельном сервере. В отчетах о медленных запросах (pgfouine) постоянно фигурировала таблица django_session.

                                После внедрения этого нехитрого решения нагрузка на сервер с базой данных заметно снизилась.
                            –1
                            Очень полезная статья. Спасибо! Особенно понравилась идея из раздела «Кеширование».
                              +1
                              Почему схема БД не позволяла использовать select_related? Просто модели были не связаны или что?
                                0
                                Они связаны необязательными связями.
                                  +1
                                  Это не предлог.
                                  Note that, by default, select_related() does not follow foreign keys that have null=True.

                                  Но это ж только by default.
                                  You can refer to any ForeignKey or OneToOneField relation in the list of fields passed to select_related. Ths includes foreign keys that have null=True (unlike the default select_related() call).
                                +2
                                А что за модуль в итоге отвечающий за страницы получился? И где форк pyblicauth лежит? ;)
                                  0
                                  Скрин который для django-mptt идет, это функционал из коробки? Я до сих пор для админки куски из fein-cms юзал…
                                    0
                                    Да, это кусок fein-cms; про него не писали.
                                    +2
                                    А не хотите выложить ваши доработки publicauth куда-нибудь в open-source?
                                      0
                                      Возможно, но пока они сыроваты
                                      +1
                                      А почему нету django-annoying и django-command-extensions? Очень удобные штуки.
                                        0
                                        django-annoying используем) полезняшки
                                          0
                                          Что именно из него?

                                          Лично я не понимаю, чем вот это:
                                          @render_to('template.html')
                                          def foo(request):          
                                              bar = Bar.object.all()  
                                              return {'bar': bar}
                                          

                                          лучше этого:
                                          def foo(request):
                                              bar = Bar.object.all()  
                                              return render_to_response('template.html', {'bar': bar}, context_instance=RequestContext(request))
                                          

                                          К тому же, HttpResponse, в который все и приходит в итоге, понимает ряд дополнительных параметров, которые иногда нужны: mimetype, status, content_type.

                                          И остальное в том же духе. Набор разнородной фигни.
                                            0
                                            Ну вот когда нужны параметры HttrResponse, тогда и пишем по-старинке.
                                            А render_to улучшает читаемость, имхо.
                                            Плюс view-ункция возвращает словарь, и я могу, например, написать декоратор, который будет с нима что-нить делать.
                                              0
                                              Мне в render_to нравится только то, что название шаблона стоит рядом с названием метода. Это удобно, если метод большой. Пожалуй, можно дописать поддержку параметров и положить в свой модуль.

                                              Но вообще, это уже на грани добра и зла, мне кажется.

                                              Недавно видел проект, в котором реализован тег google-analytics. То есть, программист подключает новую зависимость только для того, чтобы не копировать в проект 5 строк кода руками!

                                              Это стремление к бесполезной красоте кода (которой иногда находят даже какие-то псевдо-логичные объяснения) — симптом обсессивно-компульсивного расстройства :-)
                                                0
                                                А что если у меня 10 проектов, в которых нужен google analytics?
                                                  0
                                                  Ну, круто. Значит, продуктивно работаете.

                                                  Новая зависимость на такую ерунду потенциально принесет больше проблем, чем пользы. Скопипастить код гугла (а вам же нужно где-то брать его ID) будет быстрее, чем прописывать зависимость и подключать приложение. Да, в вашем шаблоне будет, о боже, неприкрытый js-код.
                                                    +1
                                                    ))
                                                    Я и сам с этими мыслями борюсь. Скопипастить — это ж так «очевидно»…
                                          +1
                                          прошу прощения, django-extensions лучше брать с гитхаба
                                          0
                                          Вот это от души! Спасибо, ребята. Круто.
                                          • UFO just landed and posted this here
                                              0
                                              Там в джанго все так интересно, обязательно нужно будет написать на нем что-нибудь)
                                                +1
                                                Мне нравится django-debug-toolbar, использую в основном для отслеживания запросов к базе.
                                                  0
                                                  Да, кстати))
                                                  0
                                                  Я видел одну переделку publicauth на github, это не ваша?
                                                    0
                                                    Не наша. Там было что-то подобное?
                                                      0
                                                      Вообще я не уверен что это именно переделка или это я щас не ту либу нашёл которую в прошлый раз видел, но подход похож github.com/omab/django-social-auth
                                                      Правда слишком много кода почему-то, в моей publicauth по-моему проще всё как-то :)
                                                        0
                                                        Во, там выше в комментах дали правильный линк github.com/klen/django-netauth
                                                      0
                                                      На сайте у Вас миниатюры изображений круглой формы. Я так понимаю для этого использовался sorl-thumbnail со специальными настройками? Если да, можно пример? :)
                                                        +1
                                                        Там обычные квадратные превьюшки, это css.
                                                        +1
                                                        Выложите, если не жметесь, библиотеку с авторизацией, которую «основательно допилили». Так Вы сможете помочь любимому фреймворку.
                                                          0
                                                          Большое спасибо, отличный топик
                                                            0
                                                            Обещали выложить авторизацию, а воз и ныне там. Пожалуйста, выложите! Ведь не хочется изобретать велосипед!
                                                              0
                                                              Вот отличное приложение: github.com/krvss/django-social-auth
                                                              В том числе поддержка российских соц. сетей: вконтакте, одноклассники, майл.ру

                                                            Only users with full accounts can post comments. Log in, please.