2 года на Django

Иван Сагалаев

Яндекс

Киев, Exception #06, сентябрь 2007

О чем пойдет речь

Что круто

Что не круто

Приемы

"Охотничьи рассказы"

Django — вещь!

Фреймворк

Библиотека — вспомогательные функции, которые программист использует в своем workflow.

Фреймворк — workflow, в который программист вставляет свои вспомогательные функции.

Интеграция

На практике менять ключевые компоненты Джанго — ORM, urlconf, шаблоны — либо нереально, либо бесполезно.

Но вы не хотите этого делать!

{% url %} не работает при слишком слабых связях.

Джанго — это просто Питон

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

Рекомендуемое поведение есть, но вы можете полагаться просто на свой извращенный вкус.

Тупые шаблоны

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

Шаблонный DSL

Традиционно:

<a href="
  {% if item.single %}{% url show %}{% endif %}
  {% if item.important %}{% url popup %}{% endif %}
  {% if item.many %}{% url list %}{% endif %}">...</a>

Красиво:

<a href="{% item_link item %}">...</a>

Паттерн "Форма"

Пользоваться newforms правильно и хорошо

Подключаемые приложения

Разбиение проекта на приложения часто недооценивают. А зря.

Тестирование

Джанговцы рекомендуют unit-тесты и doc-тесты.

Юнит-тесты можно запускать по отдельности — очень удобно в отладке.

Приятный инструментарий: TestClient, assertContains, assertFormError, assertTemplateUsed.

Fixtures

Обобщенный формат начальных данных проекта, без которых он не может работать

Оформление тестовых кусочков

Комфортно в транке

Один из немногих open-source проектов, где использовать разрабатываемый код удобно и довольно безопасно (мы в Яндексе так и делаем)

Код — очень хорошая документация

Следите за django-developers

«Отстой ваша Джанга!»

Авторизация

Любая попытка прикрутить внешнюю авторизацию выливается в какой-нибудь вид хаков

CMSные уши

Загрузка данных через память

Админка не умеет ничего кроме CRUD

Ограниченные ACL-права

Репликация

Джанго умеет общаться только с одним сервером БД

Бранч multi-db поддерживает разделение серверов по моделям, а не по операциям

Кунг-Фу

Организация настроек

Разделите настройки

MEDIA-файлы

Вы наверное делаете по-другому. Но...

proj/       —  папка-контейнер
  media/     —  upload, сюда показывает MEDIA_ROOT
  proj/      —  код проекта (под SVN)
    media/   —  скрипты и стили,   
      js/       которые надо отдавать статически
      css/

MEDIA_URL, MEDIA_URL/js и MEDIA_URL/css алиасятся в свои папки средствами веб-сервера

Окружение запроса

globals.py

import threading
globals = threading.local()

middleware.py

class MyMiddleware:
  def process_request(self, request):
    from globals import globals
    globals['user'] = request.user

Наследование queryset'ов

Когда на объекты запросов нужно повесить дополнительные данные, которые нельзя выбрать в том же запросе

А выбирать их отдельно для каждого отдельного объекта дорого

Article.objects.add_info_from_slow_storage().filter(...)

Наследование queryset'ов

class MyQuerySet(QuerySet):
  def _get_data(self):
    result = super(MyQuerySet, self)._get_data()
    ext_info = get_ext_info(r.id for r in result)
    for r in result:
      r.ext_info = ext_info[r.id]
  
  def _clone(self, klass=None, **kwargs):
    if klass is None:
      klass = MyQuerySet
    return super(MyQuerySet, self)._clone(klass, **kwargs)
  

testserver

./manage.py testserver fixture1 fixture2 ...

«Охотничьи рассказы»

Эволюции схем

Известная претензия к Джанго — не умеет автоматически менять схему данных по модели

Но в Яндексе даже создание схемы делается вручную SQL-скриптами

"Мало ли, вдруг по репликам неправильно разойдется"

Репликации или кеширование

Репликация — способ размазать нагрузку на чтение по нескольким MySQL-серверам

Большой минус — Джанго этого не умеет.

Репликации или кеширование

Размазать нагрузку на чтение с тем же успехом можно и по Memcached-серверам.

Но это не работает для "расчетных" сервисов, где очень много вариантов ответов. Типичный пример — сервер расписаний поездов.

Memcached

Когда вам говорят, что для кеширования надо использовать именно memcached — верьте!

Главная фишка — единый глобальный кеш на все доступные серверы без выделенного балансировщика.

Стратегия кеширования

Профилирование

В Джанго нет профилирующего WSGI-обработчика...

Напишем свой!

Профилирование

from django.core.handlers import wsgi

class ProfileWSGIHandler(object):
    def __init__(self):
        self.handler = wsgi._WSGIHandler()
    
    def __call__(self, environ, start_response):
        profile = hotshot.Profile(...)
        return profile.runcall(self.handler, environ, start_response)

def install_profiler(path):
    if wsgi.WSGIHandler.__name__ != 'ProfileWSGIHandler':
        wsgi._WSGIHandler = wsgi.WSGIHandler
        wsgi.WSGIHandler = ProfileWSGIHandler
        ProfileWSGIHandler.path = path

Спасибо за внимание!

Задавайте вопросы.