25 августа 2013 г.

django favicon.ico robots.txt

Есть некоторая проблема с такого рода файлами в django. Они предполагаются находящимися в корне, а статика как правило раздаётся из «подкаталога» (например, /static/). Да, в случае favicon.ico его можно указать в meta-тегах страницы, но в некоторых случаях, например, при отдаче 500 ошибки или в любом другом случае без учёта корневого шаблона с meta-тегами, некоторые браузеры всё равно запрашивают /favicon.ico из корня, напрягая логи WARN-ошибками 404. Потому удобно в urls.py перенаправлять редиректом на реальные расположения файлов.
url(r'^favicon\.ico$', RedirectView.as_view(url=settings.STATIC_URL + 'images/favicon.ico')),
url(r'^robots\.txt$', RedirectView.as_view(url=settings.STATIC_URL + 'robots.txt')),
В случае robots.txt можно отдавать как шаблон, если удобнее (можно и mime задать, начиная с 1.5, емнип)
url(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt', content_type='text/plain')),
Для старых версий django это будут процедурные вьюшки redirect_to и direct_to_template соответственно, приводить код тут не буду за бессмысленностью.

12 июля 2013 г.

linux eclipse crash libsoup

Eclipse крашится вместе с JRE (причём любой, опен или сановской) на новом libsoup в момент попытки вывода всплывающего окошка почти в любом редакторе.
C  [libsoup-2.4.so.1+0x6d9b1]  soup_session_feature_detach+0x11
Пришлось порыться и перепробовать несколько вариантов, но нагуглил решение. Помогает добавление
-Dorg.eclipse.swt.browser.DefaultType=mozilla
в eclipse.ini или параметры запуска.

з.ы. баг на багтрекере: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405786

11 июля 2013 г.

svn-проект в git-проект (с googlecode на github)

Просто памятка. Переносил несколько проектов с разных svn-репозиториев (googlecode, например). Делается просто, да и материал в сети есть на этот счёт. Выкачиваем репозиторий и превращаем его в git-svn репозиторий:
git svn clone https://projectsvn.googlecode.com/svn/trunk --authors-file=/home/user/authors --no-metadata
Файл authors нужен, чтобы сопоставить svn-юзеров с git-юзерами в новом репозитории, у меня он был такой:
user@gmail.com = darkbarker <user@gmail.com>
(no author) = darkbarker <user@gmail.com>
"(no author)" нужен для коммитов без автора (например, инициальный коммит svn-сервера).
Дальше можно отфильтровать дерево коммитов, исключив пустые коммиты, которые при конвертации образуются по разным причинам, т.к. не всем изменениям в svn-коммитах соответствуют изменения в git-коммитах (изменения в директориях, например).
git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' HEAD
Это отпочкует ветку от низа дерева и перенесёт туда master, оставив старые коммиты в старой ветке git-svn. Ну а дальше как обычно, заливаем в новый существующий git-репозиторий (надо создать его, конечно).
git remote add origin git@github.com:user/projectgit.git
git push origin master
Для bitbucket то же самое потребуется сделать:
git remote add origin https://user@bitbucket.org/user/projectgit.git
git push origin master

9 июля 2013 г.

midnight commander user menu hardlink

Очень бесит создание хардлинков в midnight commander -- запрашивает пустым окошком имя линка и кладёт его в текущую папку (актуальная версия 4.8.7). Так как я довольно часто использую хардлинки для общих файлов разных проектов, написал мелкий скриптик на user menu. Редактируется через "редактировать файл маню -> пользовательский".
+ t t
H       Hardlink to other panel
        set %t
        while [ -n "$1" ]; do
         ln "$1" "%D"
         shift
        done
Теперь выделяем файлы, нажимаем F2, "Hardlink to other panel" и линки с теми же именами оказываются на противоположной панели. Круто.

27 июня 2013 г.

django: что-то типа select_related для m2m

Заметка о проблемах со множественными выборками из БД при обходе списка сущностей в случае many-to-many связей.

Проблема

У нас есть такая схема:
# категория афиши
class CategoryPlaybill(models.Model):
    ...

# афиша
class Playbill(models.Model):
    categories = models.ManyToManyField(CategoryPlaybill, ...)
    ...

# проведение афиши
class ConductingPlaybill(models.Model):
    playbill = models.ForeignKey(Playbill, ...)
    ...
Итак, есть типы событий. Есть события по многие-ко-многим (событие может входить в несколько категорий). А есть их так называемые проведения — событие с конкретной датой, временем, местом. Мне надо получить проведения событий с разбивкой по категориям: категория1=>(список проведений), категория2 =>(список проведений).

Приходит в голову решение в лоб:
cond_playbill_list = ConductingPlaybill.objects.select_related().all()
cond_playbill_map = {}
for cond_playbill in cond_playbill_list:
    cats = cond_playbill.playbill.categories.all()
    for cat in cats:
        if cat not in cond_playbill_map:
            cond_playbill_map[cat] = []
        cond_playbill_map[cat].append(cond_playbill)
Но это решение ожидаемо даёт кучу запросов в БД на предмет SELECT FROM categoryplaybill WHERE playbill_categories.playbill_id = N для каждой итерации внешнего цикла. Дело в том, что select_related не тянет playbill_categories и ниже.

django: шаблонизатор не отображает defaultdict

Проблема

Шаблонизатор Django некорректно отображает словарь, созданный через defaultdict. На этот счёт есть тикет #16335.

21 июня 2013 г.

django: QuerySet расширяемый Manager

Приспособился использовать небольшой QuerySetManager для удобства добавления налету методов в QuerySet модели. Т.е. просто прописыванием в классе модели соответствующий QuerySet расширяется, довольно удобно, если надо писать сложные менеджеры для модели. Сам класс выглядит так:
from django.db import models

class QuerySetManager(models.Manager):
    def get_query_set(self):
        return self.model.QuerySet(self.model)

    def __getattr__(self, attr, *args):
        return getattr(self.get_query_set(), attr, *args)
Внутрь класса где-то рекомендовалось добавить полем "use_for_related_fields=True", но работает без него. Зато не работает без __getattr__, пишет: 'RelatedManager' object has no attribute 'useractive', вопреки ещё какой-то рекомендации из инета. В итоге имеем некий хак.

Используется как-то так:
class Clazz(models.Model):
    ...
    objects = QuerySetManager()
    ...
    class QuerySet(models.query.QuerySet):
        def useractive(self,date):
            return self.filter( Q(active=True) & (Q(date__isnull=True)|Q(date__gte=date)) )
И потом во вьюшках:
Clazz.objects.useractive(now).order_by('date')