About Blog Dev | Alfa Romeo SZ Conkeror wishlist

Archive for October, 2007

Связанные объекты

Сегодня наконец-то отбросил свою лень в сторону и сделал то, о чём так долго твердили большевики! :)

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

В Джанге, как известно, встроен свой механизм аутентификации, который часто бывает довольно удобен (самое большое удобство заключается именно в его встроенности - интеграции со всем джанговским хозяйством), но имеет одну принципиальную проблему: модель пользователя самого практически нереально расширять.1 Пока из адекватных рабочих путей (т.е. даже если смотреть по сторонам, не обращая внимания на слова “гарантированный”, “официальный”, “документированный” ;) есть только создание отдельной модели - профиля (всем заинтересованным - читать пост Джеймса Беннетта, благо он хорошо описал2), но при этом сразу возникает другая проблема - профиль, живущий в отдельной модели, подтягивается к объекту юзеру в общем случае отдельным запросом.

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

Штука эта - несколько функций, которые позволяют загружать обратные связи за один запрос. Т.е. если мы получаем 5 постов в блог, а потом к ним комментарии - это выходит 2 запроса в базу, а не 6 (1 на посты и 5 на комментарии к каждому). В принципе, никакого rocket science’а нету, но я за время работы с джангой всегда изворачивался другим образом, если попадал на подобные грабли - не всегда это было лучше, но кое-как выходило. :-) И вот эти функции я использовал для подгрузки профилей к пользователям в отображении комментариев здесь, что уменьшило количество запросов на каждый пост в разы. :)

Я ещё успел натолкнуться на проблему, что рассчитано это было на что-то подобное “последним двадцати постам или картинкам” - уникальным объектам, и из-за этого кэш получал только первый объект из тех, кто его хотел. А в случае с комментариями такое не прокатывает никак, тут один и тот же человек комментирует несколько раз. :-) Это меня и заставило разобраться в коде и добавить поддержку неуникальных объектов.

Думаю, что прямо здесь код приводить особого смысла нету, но вот сами функции, а тут их использование.

P.S.После написания этого поста и игр с sup мне захотелось сделать сноски, подобные тем, что есть у Адама Гомаа. :-)

1 -

мне кажется, что с помощью переделки модели юзера в создающуюся динамически эту проблему можно решить.

2 -

хотя я использую AutoOneToOneField Ивана Сагалаева, но большой роли это не играет. :)

Линухсы, линухсы…

Линукс не был моим основным десктопом (точнее, вообще не появлялся на нём) в течении вот уже трёх с половиной лет (краткое появление в сентябре прошлого года не считается, он появился по работе и быстро исчез ;), но вот с пару неделек назад я подумал - ну в любом случае при использовании флюксбокса мышка нужна меньше, чем при использовании винды.

И поставил себе ALT Linux. О самом дистрибутиве - впечатления сугубо положительные. Если не считать отсутствие dpkg’шных возможностей по расставлению приоритетов для разных репозиториев (которыми я пользовался сугубо из-за устаревания testing, не то что stable), то все прелести apt на месте. Отличная система конфигурации сетевых интерфейсов (до этого мне дебиановская казалась лучшим вариантом, но теперь я знаю правду ;), етц, етц. Я в принципе не люблю sysconfig (она в FC/RHEL неадекватно загажена тоннами несортированых файликов настроек), но в Альте он подобен /etc/default Деба - всё достаточно простенько и ненапряжно. Разбиение на пакеты - отличное, бьют достаточно мелко; делать свои - одно удовольствие: рпм заметно проще деба пишется, а в альте ещё и немалое количество макросов, облегчающих жизнь и убивающих рутину. :)

В общем, понравился мне дистр. :)

Но из минусов - даже в нестабильной ветке сейчас идёт всё ещё ядро 2.6.18. В принципе, меня это никак не напрягало бы, но из-за этого не работал нормально hibernate/suspend и 3D. Но я бы на это дело даже забил, невелика потеря, если бы не питон. А в Альте он есть только 2.4 без вариантов. :( Я подёргался и написал письмо в рассылку, результатом которого явилось решение, что будет абсолютный переход на 2.5 (без сохранения 2.4), но не раньше Нового Года. Компилить питон руками мне никак не улыбалось, и я решил перейти на что-то более свежее.

На самом деле выбора особо и не было - я поставил свежую Убунту (прошлая версия которой наотрез отказывалась работать на моём ноуте ;). В ней, естественно, питон2.5, работает хибернейт и 3д рендеринг, и вообще всё отлично относительно большинства других вариантов. Если бы не одно но - шрифты. Я потратил суммарно часов 5-6 времени, заставив их выглядеть заметно лучше, чем они были в начале. И всё равно мой блог выглядит в винде на порядок лучше (особенно код). Да, я могу подправить дизайн своего блога, но я не могу подправить дизайн ещё целого ряда других сайтов.

Из чего следует печальный вывод, что видать я останусь на винде. :( Если, конечно, не случится чуда и шрифты вдруг не улучшатся. :)

Однако я хотел поделиться одной штукой - я за время этих экспериментов попробовал tiling wm’ы, и это просто невероятная штука! :) В конце-концов по совокупности фич и удобству (а также идеологическим соображениям ;) я остановился на xmonad. Вся идея заключается в том, что окна никогда не перекрываются (т.е., есть специальный слой для плавающих окошек - типа контакт листа или xmms’а какого, но это исключение и вообще на помойку такие окошки ;). Их можно туда-сюда совать, увеличивать и уменьшать размер относительно друг друга, расставлять в разные лейауты (мозаика, сетка, табы) и т.д.

В общем, рекомендую. Хотя бы попробовать. Мой конфиг можно найти тут (Config.hs).

Проверяйте ввод :)

Apache + mod_wsgi + Django

Меня тут попросили описать то, как я запускаю джанговские приложения в апаче. Я решил не растягивать резину в долгий ящик и просто привести свой конфиг с комментариями. :)

<VirtualHost *>
    ServerAdmin piranha@piranha.org.ua
    ServerName piranha.org.ua
    ServerAlias www.piranha.org.ua

    # директива говорит о том, что это конкретное приложение будет исполняться
    # в процессе-демоне с названием piranha
    WSGIProcessGroup piranha
    # Собственно описание этого демона. 2 процесса, максимум 1000 запросов.
    # Сайт не нагруженный, больше и не надо. :)
    WSGIDaemonProcess piranha user=piranha group=www-data threads=2 maximum-requests=1000
    # Главная, практически, директива. Файлик с описанием приложения. См. ниже.
    WSGIScriptAlias / /home/piranha/web/byteflow/byteflow/django.wsgi

    # Решил оставить, чтоб не забывали про него. :)
    # Кеширование картинок и прочих статических файлов.
    <IfModule mod_expires.c>
        <FilesMatch "\.(jpg|gif|png|css|js)$">
            ExpiresActive on
            ExpiresDefault "access plus 3 days"
        </FilesMatch>
    </IfModule>

    # Описание расположения статических файлов.
    Alias "/admin-media/" "/usr/local/lib/python2.4/site-packages/django/contrib/admin/media/"
    <Location "/admin-media/">
        SetHandler None
    </Location>

    Alias "/media/" "/home/piranha/web/byteflow/media/"
    <Location "/media/">
        SetHandler None
    </Location>

    # Логи. ;)
    LogLevel warn
    CustomLog /home/piranha/web/logs/piranha.access.log combined
    ErrorLog /home/piranha/web/logs/piranha.error.log
</VirtualHost>

А вот тот самый файлик, в котором описывается, как запускать приложение:

import sys
import os
import os.path

sys.path.insert(0, os.path.dirname(__file__))
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()

Кратко и незамысловато. Годится для любого проекта в силу независимости от места расположения. :)

Вот и всё. Файлик django.wsgi лежит в директории проекта, джанга лежит в пути Python‘а (у меня вот в /usr/local/, потому как последний trunk и пакета для него, естественно, нету), всё работает прекрасно.

P.S.И, естественно, апач надо релоадить (apache2ctl graceful) после изменений в конфиге или в питон-коде приложения.

Кеширование ContentType в память

Сегодня обсуждали немного generic relation’ы из Джанги, и пришли к выводу, что неплохо было бы сами ContentType‘ы закешировать прямо в память - мы постоянно используем один и тот же набор из нескольких типов (модельки, которые можно тегать и ставить рейтинги), и кеш даёт гарантию того, что для них будет всего 1 запрос в базу за всё время жизни апачевского ребёнка.

Я даже написал в django-users, на что мне Малькольм указал на уже существующий кеш, который, однако, работает, только если у меня уже есть модель. А мне-то наоборот, надо её получить!

Вылилось в первом приближении всё это в 10 минут вечером (почему-то при обдумывании этого на работе мне в голову лезли всякие непристойности с кучей кода) и замену метода get у менеджера модели ContentType. Кеш вышел рабочим, но тупым - отдельным от существующего джанговского, хранящим результаты выборки в словаре с ключом только по названию модели.

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

Короче, много времени это не заняло. Встречайте, а вдруг кому-то пригодится? :)

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

Вообще наверное лучшим решением будет подгрузка всех типов сразу на старте, построение словаря с уникальными названиями моделей (те, на которые и база данных бы не ругалась при выборке без имени приложения), но я пока не придумал, как бы это сделать. :)

Seek’n’read

Ощутил в полной мере только что, чем грозят флешки. Вот казалось бы, не слишком быстро, но жить можно:

[root@(none) root]$ hdparm -t /dev/discs/disc0/part1
/dev/discs/disc0/part1:
 Timing buffered disk reads:   26 MB in  3.05 seconds =   8.52 MB/sec

Но время поиска-то какое:

[root@(none) root]$ time vim -c :q
real    0m 0.97s
user    0m 0.82s
sys     0m 0.12s

Это мы себе ASUS WL-500g приобрели. Буржуйская, однако, штука - вай-фай по всему дому, етц. Забытые ощущения консольки под рукой. ;) Удобен тем, что туда в усб-порт вставился и без всяких проблем работает мой AC8700 от people.net - других вариантов инета просто нету, а этот оказался удивительно неплохим. ;)

Вообще думал на него сначала поставить nginx, trac, mercurial… Но вот посмотрел на эти скорости и задумался. :D Может, перееду с компа на ноут, а комп оставлю для таких делов?