28 дек. 2009 г.

Django compressor и фильтры.

В прошлом посте я писал о django compressor. Не ясно было почему компрессор ничего не делает (по умолчанию) с CSS-файлами (кроме очевидного – сборки в один файл и кеширования).

Присмотревшись внимательней компрессору, удалось выяснить, что есть в нем возможность использования csstidy, jsmin, yuicompressor и google closure для сжатия css и js файлов. Однако, процесс установки и настройки этих инструментов, не так уж и прост (по крайней мере yuicompressor и google closure).

jsmin ставить отдельно не нужно. Он входит в “стандартный набор” и даже включен по умолчанию в настройках django compressor опцией


COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']


С csstidy у меня ничего не вышло. После установки csstidy на наш с Дениской debian и подключения фильтра:


COMPRESS_CSS_FILTERS = ['compressor.filters.csstidy.CSSTidyFilter']


словил 500 ошибку - фильтр не знал глобальную переменную css.


# django_compressor/compressor/filters/csstidy.py

...

17.         tmp_file.write(css)

...


YUI Compressor.

Сходил и забрал по ссылке http://yuilibrary.com/downloads/#yuicompressor.

Поставил openjdk-6-jre (советуют ставить последний, aptitude search "?provides(java-runtime)").


apt-get install openjdk-6-jre


Положил файл yuicompressor'а в /var/www/. Не спрашивайте зачем и почему – так в голову взбрело.

Добавил в settings.py моего django-проекта:


COMPRESS_JS_FILTERS = ['compressor.filters.yui.YUIJSFilter',]

COMPRESS_CSS_FILTERS = ['compressor.filters.yui.YUICSSFilter',]

COMPRESS_YUI_BINARY = 'java -jar /var/www/yuicompressor-2.4.2.jar'


Google closure пока не осилил. При, казалось бы правильных настройках:


COMPRESS_JS_FILTERS = ['compressor.filters.closure.ClosureCompilerFilter',]

COMPRESS_CSS_FILTERS = ['compressor.filters.closure.ClosureCompilerFilter',]

COMPRESS_CLOSURE_COMPILER_BINARY = 'java -jar /var/www/compiler.jar'


Попытка сжать css и js отпадает по таймауту. Возможно Вам известна причина? Напишите, я хочу сравнить производительность и результаты работы фильтров.

Возможно, кстати, кому-то удалось заставить работать csstidy?

Django compressor.

Давненько заглядывался на django-compress, но всякий раз пугался групп для css и js файлов. Дело в том, что процессе непрекращающегося deadline’а я постоянно дописываю стили в новые файлы или прям в шаблоны. Вечно потом пытаюсь разобраться в этом беспорядке, но как правило, прихожу к выводу, что некоторым стилям, или “приглашенным” js-скриптам в общем наборе делать нечего.

Пример: на сайте http://72arenda.ru/ есть форма заказа. Сейчас jquery + ui грузятся для всего сайта, но раньше было правильней – набор грузился только на странице бронирования, где эти скрипты и были востребованы. Подобных примеров в моих проектах много.

Альтернатива django-compress’у - Django compressor, использует другой подход. После подключения приложения ‘compressor’ в INSTALLED_APPS нужно прям в шаблонах заворачивать конструкции вызова или описания css или js файлов в специальные templatetag’и.

Пример с сайта:


{% load compress %}



{% compress css %}

<link rel="stylesheet" href="/media/css/one.css" type="text/css" charset="utf-8">

<style type="text/css">p { border:5px solid green;}</style>

<link rel="stylesheet" href="/media/css/two.css" type="text/css" charset="utf-8">

{% endcompress %}



{% compress js %}

<script src="/media/js/one.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript" charset="utf-8">obj.value = "value";</script>

{% endcompress %}


Django compressor заменит стили на

<link rel="stylesheet" href="/media/CACHE/css/f7c661b7a124.css" type="text/css" media="all" charset="utf-8">


а js на



<script type="text/javascript" src="/media/CACHE/js/3f33b9146e12.js" charset="utf-8"></script>


То есть, на кешированные, собранные в один файл, почищенные наборы стилей и скриптов.



UPD. Как выяснилось поздней, фильтры по умолчанию ничего не делают с содержимым файлов - не жмут, не чистят, не обфусцируют. Для активации фильтров нужно ставить yui-compressor или google closure, т.к. csstidy у меня работать отказался – жалуется, что не знает переменную css.



Compressor не делает ничего, если включен дебаг режим (DEBUG = True).



Компрессору нужен BeautifulSoup, так что проследите, чтоб он у вас был установлен.



К сожалению, пока не удалось разобраться в том, что является критерием “перестройки” кеш-файлов. В скриптах есть строка “Rebuilds the cache once a day if nothing has changed.” – Очевидно, перестройка происходит чаше, если что-то меняется (я проверял. каждый раз, когда я что-то менял, происходила “перестройка”).



Подобные инструменты нужно использовать в паре с методикам и описанными на странице http://code.google.com/p/django-compress/wiki/FarFutureExpires для достижения большего эффекта.



Успехов в освоении Django compressor и с наступающим!

Снипет для пользовательского контента в шаблонах

Очень простой и, наверняка, не слишком правильный способ вставлять html-хуки в шаблоны, содержимым которых может управлять пользователь:


# models.py:



class Snippet(models.Model):

    id          = models.AutoField(primary_key=True)

    title       = models.CharField(u'название', max_length=50)

    text        = models.TextField(u'текст', max_length=5000)

    template    = models.CharField(u'шаблон',   max_length=250, blank=True, null=True)

    def __unicode__(self): return u'%s (%s)'%(self.title, self.template)

    class Meta:

        verbose_name = u'снипет'

        verbose_name_plural = u'снипеты'



# tampletetags/realtor_tags.py:



@register.simple_tag

def get_snippet(title, **kwargs):

    from realtor.models import Snippet

    try:

        return Snippet.objects.get(title=title).text

    except:

        return u''

get_snippet.is_safe = True



# в шаблонах:



{% load realtor_tags %}



{% get_snippet 'realtor-top-left' %}


22 дек. 2009 г.

Django multiple database support - теперь поддерживает множественные соединения с базами данных

Весь твиттер буквально кипит от это новости – django теперь поддерживает множественные соединения с базами данных. Фича влита в транк и описана в документации.

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


# in settings.py:



DATABASES = {

    'default': {

        'NAME''app_data',

        'BACKEND''django.db.backends.postgres_psycopg2',

        'USER''postgres_user',

        'PASSWORD''s3krit'

    },

    'users': {

        'NAME''user_data',

        'BACKEND''django.db.backends.mysql',

        'USER''mysql_user',

        'PASSWORD''priv4te'

    }

}



# in model lookups:



Author.objects.using('default').all()



# using('default') - явное указание БД для запроса. Если не указывать будет браться default


Подробней смотрите в документации! Поздравляю всех с этой новой фичей, мы давно ждали такой функциональности. Ура!

UPD. Этот пост как-то “сам собой” залез на хабр, и теперь собирает заслуженную (и не только) критику.

20 дек. 2009 г.

Django CMS – show_menu

UPD: Начиная с версии 2.1.0 beta загрузка меню тэгов происходит по новому (см. http://www.django-cms.org/news/2010/03/24/django-cms-210-beta-released/).

Сегодня попытаюсь рассказать о template tag’е show_menu в django-cms. Сам разбирался с ним методом научного тыка.

{% show_menu %}


Тэг генерирует меню навигации для текущей (выбранной, открытой) страницы.

Параметры

Show_menu принимает следующие необязательные параметры:
start_level - начальный уровень навигации,
end_level конечный уровень навигации,
extra_inactive – начальный уровень “дополнительной” навигации,
extra_active - конечный уровень “дополнительной” навигации
“Дополнительная” - это навигация по страницам, которые не являются прямыми потомками и предками текущей страницы.
Для этого тэга можно переопределить шаблон вывода, создав в шаблонах своего проекта свой шаблон cms/menu.html или передав в ещё один дополнительный параметр template. Пример:

{% show_menu 0 100 0 100 "my_new_cool_menu.html" %}


Играемся с уровнями навигации

Для тестирования работы тэга возьмем сайт-пример demo.concepter.ru, о котором я уже писал раньше. (UPD: сайта demo.concepter.ru больше нет). Итак, имеет исходное дерево сайта:
  • root 1
    • 1 level child (p, n)
      • 2 level child (p, n) of 1
      • 2 level child (p) of 1
    • 1 level child (p)
      • 2 level child (p, n) of 1 level child (p)
    • 1 level child
    • 1 level child (n)
  • root 2
    • 1 level child (p, n) of root 2
      • 2 level child (p, n) of 1 of root 2
    • 1 level child (p) of root 2
буквы в скобках – статусы. p – страница опубликована, n – “в навигации”.
На главной странице вызваны show_menu со следующими параметрами:

1. {% show_menu 0 100 100 100 %} - Вся навигация



2. {% show_menu 0 100 0 100 %} - Навигация по активному дереву



3. {% show_menu 0 100 0 1 %} - Навигация с одним дополнительным уровнем



4. {% show_menu 0 0 0 0 %} - Корневая навигация



5. {% show_menu 1 1 100 100 %} - Навигация первого уровня



6. {% show_menu 1 1 0 100 %} - Навигация по первому уровню (только активное дерево)



7. {% show_menu 0 1 100 100 %} - Навигация по перевому и второму уровню


Под активным деревом в данном случае понимаем дерево, в которое входит выбранная страница. Например, потомков root 1 активным деревом будет все, что ниже root 1 и root 1, включительно.

Независимые от активной страницы блоки навигации

Естественно, что вся навигация (1), корневая навигация (4), навигация первого уровня (5) и навигация 0-1 уровней (7) не будут меняться с изменением активной страницы (т.е. при переходе на новую страницу). Потому сразу покажу, как они выглядят для всех страниц:

Complete navigation

Level 0 navigation

Level 1 navigation

Level 0-1 navigation

Навигацию по активному дереву


{% show_menu 0 100 0 100 %}


Далее посмотрим какие страницы попадут в навигацию по активному дереву в зависимости от смены страницы.
1. root 1
2. root 2
Активное дерево развернуто, а не активное – нет. В навигации все страницы с параметрами страница “опубликована” и “в навигации”.

Навигация с одним дополнительным уровнем


{% show_menu 0 100 0 1 %}


1. root 1
2. root 2
3. 1 level child (p, n)
4. 1 level child (p, n) of root 2
В навигации есть все, что опубликовано и одновременно присутствует в навигации. Тэг честно вываливает 1 дополнительный уровень к текущей странице (потомки).

Навигация по первому уровню (только активное дерево)


{% show_menu 1 1 0 100 %}


Такой тип навигации можно использовать в паре с навигацией 0-го уровня для генерации двухуровневого меню на главной странице, как тут:
image
image
Естественно, там сделано не так, но для примера подойдет.
Далее пары “Активная страница” + содержимое навигации:
root 1 + 1 level child (p, n)
root 2 + 1 level child (p, n) of root 2
1 level child (p, n) + 1 level child (p, n)
2 level child (p, n) of 1 + 1 level child (p, n)
1 level child (p, n) of root 2 + 1 level child (p, n) of root 2
2 level child (p, n) of 1 of root 2 + 1 level child (p, n) of root 2
Очевидно, что в навигации данного типа меню присутствует первый уровень активного дерева. Как всегда, в неё попали только опубликованные страницы со статусом “в навигации”.

Резюме

С помощью данного тэга можно выстраивать навигацию любой сложности и вложенности, главное не запутаться в уровнях и активных деревьях.
Без параметров тэг инициализируется с 0 100 и 0 100, так что в некоторых случаях можно использовать просто {% show_menu %}.
Помимо show_menu в django-cms есть ещё show_menu_below_id, show_sub_menu и show_breadcrumb, использование которых может существенно сэкономить время и нервы. Хотя, какие там нервы? Django-cms – полнеищий fun.
Читайте все тоже самое, но на английском на странице http://www.django-cms.org/en/documentation/2.0/navigation/.

14 дек. 2009 г.

При не одном заполнении всех полей и соответственно правильном

Как правильно писать в тех. поддержку? Как правильно задавать вопросы? – все это вопросы не для обычного пользователя. В сущности, обычному пользователю все равно как это делать правильно. Такие знания нужны людям так, или иначе связанным с производством информационных систем, АРМ и многих других страшных слови аббревиатур. Обычный пользователь привык к мысли о том, что когнитивный разрыв между его пониманием систем, и пониманием систем программистом на столько велик, что программист скорей бог и экстрасенс, чем обычный человек. Зачем с богами разговаривать обычным языком? Ан нет - не боги горшки обжигают.

Сегодня на адрес тех. поддержки одного из наших проектов пришло письмо следующего содержания:

“День добрый,при не одном заполнении всех полей и соответственно правильном,невозможно пройти регистрацию,возможно с Вашем сайтом какие-то неполадки?”

У меня по русскому тройка, поэтому я не буду (не в праве) судить человека написавшего это. Да и не люблю я, когда люди начинают друг другу объяснять где запятые ставит, если суть ясна. Но в данном случае суть ускользает (от меня, по крайней мере).

Версия Дениса:

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

Вы что думаете? Случалось Вам получать подобные письма?