31 марта 2012 г.

Чтиво на выходные 31 марта - 1 апреля

Python

Парочка холиворов с хабра: наброс Ruby vs Python и грамотный ответ. Что бы вы ни выбрали, вы останетесь в выигрыше.

Спорная, но интересная статья про стиль кодирования и классы в python. Видно, у автора своё понимание чистоты кода.

Замечательный модуль mock станет частью unittest, и будет доступен из коробки уже в python 3.3

Вышла бета Pycharm 2.5: управление пакетами, virtualenv, remote interpreters.


Веб-разработка

Забавная браузерная MMORGP от Mozilla на HTML5 (node.js, вебсокеты, require.js, modernizr, jquery, underscore)

Шпаргалка easing-функций для описания скорости анимации.

Новый, открытый под лицензией CC шрифт с набором широко используемых пиктограмм - Entypo

Единый GUI-клиент для различных СУБД (MySQL, Postgres, MongoDB) Induction.app (OS X only)


Django

Очередная коллекция скринкаcтов про Django - http://godjango.com. Пока обновляется, надеемся так и будет в дальнейшем.

Один из многочисленных “Django design patterns”, местами тривиальный, местами же довольно толковый. Здесь, кстати, нельзя не упомянуть знаменитый Django Advice. Обязателен к прочтению, если вы с ним ещё не сталкивались.

Делаем модную штуку с помощью модного стека. ScrumBoard на Django + Backbone.js + Tastypie. Это не туториал, а уже готовый проект на GitHub`е.

Любопытная батарейка django-bakery. Позволяет превратить динамический контентный сайт в набор статических HTML, дабы избежать хабраэффекта. Ограничение: Django 1.3+, надо использовать class-based views (всем рекомендуем, кстати).
Кстати, для flask давно уже есть Frozen-Flask для этих целей.

Облака

Дыра в безопасности Scalaxy. В течение недели из-за ошибки в API можно было выкачать список всех инстансов.

Профилактические работы у Селектела привели к почти 5-часовому даунтайму виртуальных машин в облаке. В конце дня появился подробный отчёт о проблеме.

27 марта 2012 г.

Новинки Django 1.4, day 8: Timezones

Посвящается часовым поясам без DST.

Это предпоследний пост в серии Django Days. В этот раз будет затронуто одно из самых масштабных изменений в фреймворке: работу с часовыми поясами. Документация по этой теме достаточно подробная, мы попробуем рассказать это более интересно и по возможности сжато.

Что это и зачем
В Django до версии 1.4 все даты хранились и отображались для одного часового пояса, того, который указанны в настройках settings.TIME_ZONE. Теперь же появилась возможность хранить все даты в формате UTC и удобно выводить их с поправкой на часовой пояс пользователя.

Дополнительным плюсом нового подхода к хранению дат является обход проблем с переводом часов на летнее время и обратно, которые могут возникать раз в год. Например, 31 октября 2010 года, когда последний раз переводили стрелки осенью в России, время 02:10 утра по местному времени нельзя однозначно интерпретировать (так как час с 2:00 до 3:00 «проходит» дважды: до и после перевода стрелок). Для биллинговых систем это мелочью не назовёшь, поэтому лучше для машин хранить время в UTC, а выводить для людей с учётом часового пояса. Упомянутые «02:10 31 октября 2010» превратятся в понятные программистам "2010-10-30T22:10:00+04:00" и "2010-10-30T23:10:00+03:00".

Основные понятия
Объекты типа datetime в Python поддерживают указание часовых поясов с помощью атрибута tzinfo. Если атрибут заполнен, дата называется «timezone-aware», в противном случае это «naive» дата.

В новых проектах на Django 1.4, или если вы пожелали воспользоваться новой фичей при обновлении, установив settings.USE_TZ=True, Джанго использует timezone-aware даты.

Часовым поясом по-умолчанию (default timezone) называется пояс, указанный в settings.TIME_ZONE (например, 'Europe/Moscow').
Текущим часовым поясом (current timezone) считается тот, что активирован для пользователя в данный момент, об этом ниже.

Текущий часовой пояс
Чтобы показать пользователю дату и время из его часового пояса, необходимо для начала выяснить откуда он. Можно напрямую спросить пользователя и сохранить timezone в сессии, а можно воспользоваться базами вроде maxmind, угадав пояс по ip, или даже использовать Date.getTimezoneOffset() в js. Так или иначе, на основе этого выбора нам придётся активировать часовой пояс пользователя, чтобы повлиять на отображение дат и времени в шаблонах и формах.

Пример установки текущего часового пояса в middleware (из документации):
from django.utils import timezone

class TimezoneMiddleware(object):
    def process_request(self, request):
        tz = request.session.get('django_timezone')
        if tz:
            timezone.activate(tz)
Необходимая функциональность для работы с датами сосредоточена в модуле django.utils.timezone.


Шаблоны
Работа с датами широко поддерживается не только в питон-коде, но и в шаблонах:
# В данном блоке даты будут сконвертированы в парижский часовой пояс
# (а не текущий)
{% timezone "Europe/Paris" %}
    Paris time: {{ value }}
{% endtimezone %}

# В данном блоке даты будут выведены как они хранятся (UTC)
{% localtime off %}
    {{ value }}
{% endlocaltime %}
Это лишь небольшая демонстрация, в документации более подробно.

Мигрируем
1. Включаем settings.USE_TZ = True
2. pip install pytz (чтобы точней работало, см. ниже)
3. Пользователи PostgreSQL пропускают шаг, остальные конвертируют свои даты в БД из местного часового пояса в UTC (если он отличается, конечно).

Теперь ваш код уже поддерживает часовые пояса. Осталось починить некоторые места, в которых Django исправляет старый код за нас, преобразовывая naive-даты в timezone-aware. В противном случае могут возникать ошибки во время перевода на летнее время.

Для полноценной миграции пригодится уже упомянутый модуль django.utils.timezone и отлов мест, где даты в старом формате сравниваются «новыми».

pytz
Это библиотека, позволяющая удобно работать с часовыми поясами в питоне. Она включает в себя базу таймзон Олсона и неплохой API для различных вычислений с часовыми поясами. Несмотря на то, что она необязательна для работы часовых поясов в Django 1.4, разработчики настоятельно рекомендуют установить её, так как это позволит фреймворку не угадывать часовой пояс по-умолчанию при вычислениях, а также предоставляет список доступных поясов для вывода пользователю.

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

В следующий раз я подведу итог по всей серии постов, ещё раз выделив самые интересные моменты Django 1.4. Вероятно до Moscow Django Meetup №2 в блоге также появится моя презентация на эту же тему.

26 марта 2012 г.

Анонс 2-й встречи Django разработчиков в Москве

2-й Московский Django Meetup
В бизнес-инкубаторе «Incube»
проспект Вернадского, 82
5 апреля 2012, 19:00


Меньше, чем через две недели пройдет вторая встреча московских Django-разработчиков.
Регистрируйтесь и приходите, будет интересно.

Доклады
  • «Про простой и удобный деплоймент проекта» (для начинающих) 
  • «Шаблоны проектов на основе PasteScript» (для веб-студий) 
  • Django и SQLAlchemy 
  • О разработке расширяемых приложений (приложений с плагинами) 

Организуют встречу сами разработчики, а именно Валентин Домбровский, Михаил Корнеев и Виталий Коробкин. Двое последних ещё и выступят с докладами.

Кроме того, мы там тоже будем в полном составе (если получится). Под занавес будет небольшая презентация про фичи Django 1.4 на 10 минут от меня (по мотивам Django Days).


Регистрация

24 марта 2012 г.

Чтиво на выходные 24-25 марта

Python
Вышел Django 1.4, подробный обзор фич у нас в блоге.

Магические функций в Python (A Guide to Python's Magic Methods).

Две группы студентов провели анализ проекта Django по разным критериям и местами пришли к интересным выводам.

Юзабельная шпаргалка по Django 1.4 от компании RevSys, в которой работает Якоб Каплан-Мосс.

Javascript
4-я часть Practical HowTo - Build a Contacts Manager Using Backbone.js от Nettuts+

Большая коллекция отборных миниатюрных JS-библиотек

Source maps: как это может улучшить разработку на CoffeScript и не только

Webdev
Интересная статья для фронтенд-разработчиков с говорящим названием: About HTML semantics and front-end architecture (не могли пройти мимо, ибо в конце упоминается БЭМ).

OAuth 2.0 Playground от Google

Пара полезняшек для поклонников редактора Sublime:
интроспекция кода, автоимпорт и пр. - https://github.com/Kronuz/SublimeCodeIntel
внушительный каталог прочих расширений и менеджер расширений - http://wbond.net/sublime_packages/community

Дизайн
Хорошая статья на тему элементов в дизайне навигации (не путать с навигационным дизайном) - The Elements Of Navigation, Smashing Magazine.

Прочее
Instructables - огромный DIY-портал для гиков и не только. Там и Arduino, и моды лаптопов, и починка всякой всячины в домашних условиях... Однозначно полезный ресурс для людей с прямыми руками.

20 марта 2012 г.

Новинки Django 1.4, day 7: Templates

Седьмой пост в серии «Django Days», настал черёд рассказать про новые теги и другие вкусности шаблонов.

Тег {% elif %}
Для кого-то это чуть ли не главная фича 1.4 ;) Если у вас сложная логика в шаблонах, то теперь она будет выглядеть чуть по-проще.

Key-value аргументы для пользовательских тегов
Теперь можно использовать key-value аргументы для тегов наряду с обычными позиционными аргументами, а именно:
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
Реализуется это всё через привычные args и kwargs:
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
    warning = kwargs['warning']
    profile = kwargs['profile']
    ...
    return ...
assignment-теги
Некоторые теги в отличие от simple_tag, не обязаны выводить что-то в шаблон, им достаточно лишь модифицировать контекст рендеринга шаблона (например, встроенный {% with %}).  Вот как можно использовать подобный тег для вывода времени:
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
The time is {{ the_time }}.
С целью упрощения создания таких пользовательских тегов теперь можно использовать декоратор assignment_tag:
@register.assignment_tag
def get_current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

Контекстные пометки для перевода
В Django 1.3 появилась возможность задавать контекст для переводимых строк с помощью функций pgettext() и ngettext(), что лишь частично решило проблему локализации коротких фраз, которые могут иметь различный перевод в зависимости от контекста. Теперь его можно передать прямо в шаблоне:
{% trans "May" context "month name" %}
{% trans "May" context "verb" %}
{% blocktrans with name=user.username context "greeting" %}Hi {{ name }}{% endblocktrans %}

Тег {% static %}
Файлы из STATICFILES_STORAGE можно теперь отдавать через спецтег:
{% load static from staticfiles %}
<img src="{% static "css/base.css" %}" />
Наиболее полезен новый тег будет тем, кто хранит статику не локально, а в CDN, например, на S3, либо другим нестандартным образом. В остальных случаях этот тег эквивалентен {{STATIC_URL}} перед началом файла.

Также появился новый тип хранилища storage.CachedStaticFilesStorage, позволяющий добавлять к именам файлов из статики их md5-хэш, чтобы гарантированно инвалидировать кэш css и js, картинок и т.п.

Фильтр truncatechars
В это трудно поверить, но только сейчас через 4,5 года в состав фильтров по умолчанию попал truncatechars, обрезающий строку до определенного количества символов и завершающий её многоточием. truncate_words по-прежнему доступен.

It's not the end
На очереди пост про поддержку временных зон, завтра-послезавтра опубликуем.

19 марта 2012 г.

Новинки Django 1.4, day 6: Шаблон проекта

Продолжим начатую в прошлый раз тему про новую структуру приложений. Напомню, что теперь по-умолчанию manage.py находится на уровень выше, чем модуль проекта. Чтобы проиллюстрировать это, запустим ./manage.py startproject:
# создать проект blog в текущей директории
django-admin.py startproject blog
# blog
# blog/blog
# blog/blog/__init__.py
# blog/blog/settings.py
# blog/blog/urls.py
# blog/blog/wsgi.py
# blog/manage.py
# в 1.4 можно создать проект blog не в текущей, а любой другой директории
# Мы выбрали /home/futurecolors/stuff/
django-admin.py startproject blog /home/futurecolors/stuff/
# /home/futurecolors/stuff/
# /home/futurecolors/stuff/blog
# /home/futurecolors/stuff/blog/__init__.py
# ...
# /home/futurecolors/stuff/manage.py
За объяснением, для чего потребовалось выносить manage.py, обращайтесь к предыдущему посту. А сегодня мы расскажем про пользовательские шаблоны проектов и приложений, а также зачем в проекте появился файл wsgi.py

Свой шаблон проекта
Свершилось, теперь можно из коробки создавать свои собственные шаблоны проектов и приложений. То, для чего мы использовали собственный фабскрипт (батарейка tinned-django на github), а кто-то использовал PasteScript, теперь в какой-то мере можно сделать достаточно просто штатными средствами.

Создавать проект из шаблона можно разными способами:
# из папки
django-admin.py startproject --template=/home/my_project_template myproject
# из архива
django-admin.py startproject --template=/home/my_project_template.tgz myproject
# и даже из внешнего урла
django-admin.py startproject --template=https://github.com/amccloud/django-project-skel/zipball/master myproject
Последняя опция наиболее удобна, поскольку позволяет хранить свои шаблоны проектов, например, на гитхабе и разворачивать, скачивая zipball (последняя строчка из примера выше).

Вот парочка проектов, предоставляющих свои «django-сборки»:

https://github.com/xenith/django-base-template
Шаблон проекта на основе разработк mozilla

https://github.com/amccloud/django-project-skel/
Улучшенный стандартный шаблон от Andrew McCloud

У себя в студии планируем также использовать при создании новых проектов данную фичу, допилив предварительно наш tinned-django (пока что он сыроват, да и несовместим с 1.4 --template опцией).

При запуске команды генерации проекта все *.py-файлы интерпретируются как шаблоны, переменные заменяются соответствующими значениями из контекста. По умолчанию доступны project_name project_directory и secret_key, произвольные переменные можно передать в командной строке как --key=value.

Свой шаблон приложения
По схожему принципу работает создание приложений startapp:
# создаём приложение в текущей директории (старое поведение)
django-admin.py startapp myapp
# указываем папку, в которой создать приложение
django-admin.py startapp myapp ./apps
# шаблоны приложений тоже есть
django-admin.py startapp myapp --template=/home/fc/app.tgz
Это может быть полезно, если вы предпочитаете разбивать модуль с тестами на файлы, вместо единого tests.py, либо как-то иначе модифицируете приложения.

Улучшена поддержка WSGI
Серьёзно обновились доки по развёртыванию проектов c помощью WSGI, которых так не хватало. Например, появились материалы по uWSGI и gunicorn.

Вместе с этим теперь в структуре проекта присутствует файл wsgi.py примерно следующего содержания:
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Это стандартное WSGI-приложение может пригодиться для подключения Django к другим WSGI-приложениям или включения сторонних middleware. А по-умолчанию его можно использовать для развёртывания через WSGI-совместимый вебсервер.

To be continued...
Релиз Django через 3 дня, а серия постов всё не кончается. Подписывайтесь на RSS ;)

17 марта 2012 г.

Чтиво на выходные

Теперь по выходным мы будем публиковать подборки ссылок на всё интересное что у нас накопилось за неделю из интернетов.

Pycon 2012 US
Доступно видео с Pycon 2012, в том числе 3-х часовые семинары первого дня. Смотрите расписание с анонсами докладов и качайте, большинство роликов уже выложены.
В принципе, на этом можно было бы закончить, так как выходные уж точно будет чем занять, но мы дадим ещё несколько интересных ссылочек, на всякий случай.

Разное
Крутой пост на Smashing как делался newzealand.com Много интересных технических подробностей, будет интересно всем веб-разработчикам и не только.

Тот самый Бобук завёл себе линкоблог с забавным урлом
addmeto.cc. Подписывайтесь, если ещё не успели, ежедневная подбрка интересностей для гиков.

Код и коммиты
Поучительная статья «
Deleting code», раскрывающая, почему нельзя оставлять закомментированный код в исходниках. Не новый пост, но по-прежнему актуальный, мы придерживаемся подобных убеждений относительно чистого кода в Студии.

Любопытная
презентация про то, как надо писать коммиты.

Фронтенд
На Nettuts+ вышла 3-я, вероятно не последняя часть о практическом применении Backbone.js. В качестве примеров приводится создание менеджера контактов и автор статьи последовательно проходит от краткого описания моделей, логики, коллекций и прочих основ backbone до вполне развёрнутого и доступного для понимания описания реализации проекта в целом. Раз, два, три для интересующихся и сочувствующих :)

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

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

В догонку к адаптивности...
Техника “эластичных видео” на pure CSS.
Снова питон
А поклонникам Python возможно небезынтересно будет почитать крутецкую статью об анализе настроения твитов (!) с помощью, собственно, Python и библиотеки NLTK. Не для слабаков, для понимая необходим хороший уровень подготовки.

16 марта 2012 г.

Музыкальное. Rock in New Vegas

Rock in New Vegas

На досуге записали небольшую композицию, хотим поделиться:


Гитара, главная тема: Андрей Monstr Тикунов.
Пианино: Артём Голиков.
Барабаны: Виталий Олевинский.

Web-студия Future Colors & группа Faker Street.

Новые вакансии в Future Colors

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

Python / Django
Нам, как и раньше нужны сильные, уверенные в себе опытные джанговоды, готовые влиться в нашу команду и создавать с нами отличные проекты.

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

Вёрстка / Javascript
Мы любим проекты с большим количеством javascript и уважаем хорошо структурированную вёрстку, поэтому ищем хорошего фронтендера, готового совмещать в себе эти два качества.


Работая у нас, вы не будете вариться в собственном соку: процесс разработки связан с тесным взаимодействием в команде и следованием хорошим внутренним стандартам качества.

15 марта 2012 г.

Новинки Django 1.4, day 5: Структура проекта


На сегодня у нас изменения в структуре django-проектов. Они достаточно важные, поэтому рассмотрим их по-подробней.

Изменения в manage.py и структуре проектов
Docs
Discussion on django-developers

Зачем

Рассмотрим детально проблему, которую решают разработчики django в новом релизе, изменяя структуру проекта. Вот как выглядел базовый каркас, который генерила команда startproject до версии 1.4:
mysite/
    __init__.py
    manage.py
    settings.py
    urls.py
    myapp/
        __init__.py
        models.py
Недостатком данной структуры является наличие в пакете mysite исполняемого консольного скрипта manage.py, который по сути не связан с проектом и является «точкой входа». При запуске manage.py из консоли, папка mysite оказывается в sys.path и мы можем получить доступ к урлам и настройкам через import urls и import settings соответственно. Тем не менее, Django по-умолчанию предлагает импортировать урлы и настройки с указанием названия пакета (ROOT_URLCONF='mysite.urls'), вероятно, для того, чтобы не засорять пространство имён верхнего уровня. Дабы сделать подобный импорт возможным, функция setup_environ колдует с sys.path, добавляя родительскую по отношению к mysite папку, а потом возвращает sys.path в предыдущее состояние.

Не говоря о том, что это совсем непитонический путь, данных подход создавал целый ряд проблем, связанных с деплойментом, дистрибуцией приложений и т.д. Например, при добавлении родительской папки в sys.path, могли импортироваться лежащие рядом пакеты, создавая трудноотcлеживаемые проблемы.

Решение

В целях борьбы с подобной магией было предложено решение по выделению manage.py из папки проекта на уровень выше в файловой иерархии:
manage.py
mysite/
    __init__.py
    settings.py
    urls.py
    myapp/
        __init__.py
        models.py

Во-первых, эта структура должна сподвигнуть авторов новых проектов и мигрирующих старые следовать единой системе импортов. Например, ранее можно было импортировать в разных местах приложение как import myapp, так и import myproject.myapp. Теперь же все импорты пакетов, находящихся внутри mysite, должны будут однозначно включать название родительского модуля.

Во-вторых, изменение структуры позволило упростить код скрипта manage.py:
#!/usr/bin/env python
import os, sys

if __name__ == "__main__":
  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")

  from django.core.management import execute_from_command_line

  execute_from_command_line(sys.argv)

Начиная с 1.5 старый manage.py станет выдавать Deprecation warning, а в 1.6 перестанет работать совсем. Будьте аккураты при обновлении структуры проекта, если вы импортируете пакеты не единообразно, могут возникнуть проблемы с новым manage.py (т.к. раньше он маскировал эти ошибки).

Это ещё не всё

Продолжение о шаблонах проекта и приложений читайте завтра на этих выходных.

12 марта 2012 г.

Новинки Django 1.4, day 4: Админка

Сегодня настала очеред поведать про фичи версии 1.4, относящиеся к административному интерфейсу Django. Предыдущие части 0, 1, 2, 3.

HTML5 Doctype
Разработчики сменили доктайп с HTML 4.01 Transitional и XHTML 1.0 Strict на более современный так называемый “HTML5 doctype” с сокращённой записью <!DOCTYPE html>, который также заставляет современные браузеры рендерить страницы в “standards mode”, так что ничего особо нового, хотя шуму много и в чейнджлоге где-то вверху списка новшество.

Пользовательские фильтры в админке
 Начиная с версии 1.4 теперь официально задокументирован API по созданию пользовательских фильтров на страницах ChangeList с табличным представлением данных моделей. Ранее известный под именем FilterSpec, новый способ создания фильтров вполне себе приятен. Вот пример из доков с переведёнными комментариями:
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter
class DecadeBornListFilter(SimpleListFilter):
    # Человекопонятное название фильтра
    title = _('decade born')
    # Название пармаетра, корое будет фигурировать в урле
    parameter_name = 'decade'
    def lookups(self, request, model_admin):
        """
        Пары значение-заголовок для пользовательского фильтра
        """
        return (
            ('80s', _('in the eighties')),
            ('90s', _('in the nineties')),
        )
    def queryset(self, request, queryset):
        """
        Непосредственная фильтраций QuerySet 
        на основе взначения фильтра из self.value()
        """
        if self.value() == '80s':
            return queryset.filter(birthday__year__gte=1980,
                                    birthday__year__lte=1989)
        if self.value() == '90s':
            return queryset.filter(birthday__year__gte=1990,
                                   birthday__year__lte=1999)

class PersonAdmin(ModelAdmin):
    list_filter = (DecadeBornListFilter,)

Можно менять внешний вид фильтров посредством пользовательских шаблонов, динамически на основе запроса менять набор фильтров, возвращаемых функцией lookups. Стандартные фильтры типа BooleanFieldListFilter и DateFieldListFilter по-прежнему считаются "внутренним" API и не документируются, хотя никто не запрещает ими пользоваться на свой страх и риск:
class PersonAdmin(ModelAdmin):
    list_filter = (
        ('is_staff', BooleanFieldListFilter),
    )

Множественная сортировка в админке
Наконец-то стало возможно сортировать данные в ChangeList'е не только по одной колонке, а по нескольким сразу. Кроме стандартного атрибута ordering, можно задать пользовательскую сортировку через ModelAdmin.get_ordering() в зависимости от значения request или вручную через GUI. На скриншоте пример админки этого сайта (аж 4 сортировки в разных направлениях):


Новые методы ModelAdmin
Добавилось целых три метода:

ModelAdmin.save_related(self, request, form, formsets, change)
Позволяет добавить дополнительную обработку при сохранении формсетов с инлайнами после того, как родительская сущность сохранена. Метод дополняет существующие save_model() и save_formset(), позволяя вынести необхоимую пре- или пост-обработку в отдельный метод не хакая неподохдящие response_change() and response_add().

ModelAdmin.get_list_display(self, request)
ModelAdmin.get_list_display_links(self, request, list_display)
Кастомизация свойств list_dispaly и list_display_links на основе request. Например, так можно настроить разное количество колонок в зависимости от прав пользователя, получив доступ к переменной request.user.

Инлайны учитывают права пользователей
Теперь инлайны в админке разрешаю выполнять только те действия, на которых есть права у данного пользователя. Для редактирования M2M-связей используются права от связанной модели (если промеждуточная таблица создана автоматически и не имеет своих прав доступа). Ранее до 1.4 можно было редактировать любые сущности через inline-формы админки , даже если у вас не было на это прав (главное, чтобы были права на «родительскую» сущность).

ADMIN_MEDIA_PREFIX Deprecated
Добавлено
Опция ADMIN_MEDIA_PREFIX считается устаревшей и более не используется в админке для построения урлов к статике. Следуя изменениям в 1.3, связанными с появлением функциональности contrib.staticfiles, начиная с 1.4 теперь вместо ADMIN_MEDIA_PREFIX используется <STATIC_URL>/admin/. Это обратно несовместимое изменение, так что если у вас не был правильно настроен STATIC_URL и STATIC_ROOT на отдачу статики, либо вы отдавали статику админки по hardcoded-пути, стоит всё проверить перед апдейтом.

Продложение следует...
Осталось ещё несколько интересных тем, которые мы раскроем в ближайшие дни, вероятно, даже до релиза.

10 марта 2012 г.

Новинки Django 1.4, day 3: Тестирование

Продолжение серии постов к выходу новой Django 1.4 (начало, про ORM, про безопасность). Сегодня мы немного осветим фичи в тестовом фреймворке.

Поддержка браузерного тестирования
Docs
Commit 17241

Одна из заметных фич: поддержка интеграционных веб-тестов, например, с помощью Selenium. Он и подобные ему инструменты умеют запускать браузер и выполнять в нём различные действия, имитирующие поведение пользователя на странице, типа кликов по ссылкам, ввода текста в форму и подобного. Это позволяет тестировать сайты вцелом на основе приёмочных тестов (в отличие от юнит-тестов, покрывающих лишь отдельный компонент, но не взаимодействие компонентов). Также, в отличие от тестов с применением привычного django.test.client, Selenium умеет выполнять javascript и вообще ведёт себя как полноценный браузер (а вовсе не headless Client).

Стал доступен новый класс тестов django.test.LiveServerTestCase, который запускает во время теста встроенный вебсервер на localhost:8081.

Пример такого теста для админки джанги

Раньше примерно то же самое можно было сделать c помощью django-sane-testing или django-selenium. Оба эти варианта обеспечивают более тесную интеграцию с Selenium, в отличие от достаточно абстрактного LiveServerTestCase.

Пока что нормальная интеграция Windmill (альтернативный инструмент для браузерного тестирования) отсутствует, Twill не развивается уже 4 года, но фундамент API заложен.

Кстати, несмотря на то, что у Selenium есть неплохое API для питона, нам больше понравилась надстройка под названием splinter, советуем обратить внимание.

Новые assert-функции и другие улучшения в тестах
Упростились проверки HTML, генерируемого движком, для этого появились функции:

TestCase.assertHTMLEqual(html1, html2, msg=None) 
TestCase.assertHTMLNotEqual(html1, html2, msg=None)

Они игнорируют пробельные символы до и после тегов, порядок атрибутов и прочее. Масхэв для интеграционных тестов, где без проверки html порой не обойтись.

assertTemplateUsed и assertTemplateNotUsed теперь можно использовать как контекст-менеджеры.

assertQuerysetEqual обзавёлся аргументом ordered=True, это значит, что теперь можно сравнивать выборки без необходимости задавать сортировку явно.

Появился упрощенный класс django.test.SimpleTestCase. Он наследует стандартный функционал он unittest.TestCase, снабжая его новым функционалом:

SimpleTestCase
assertRaisesMessage(expected_exception, expected_message, callable_obj=None, *args, **kwargs)

Разновидность unittest.assertRaisesRegexp с той лишь разницей, что expected_message не регулярное выражение.

assertFieldOutput(self, fieldclass, valid, invalid, field_args=None, field_kwargs=None,empty_value=u'')
Проверка того, как ведёт себя поле формы, принимая соответствующие значения.
В примере ниже поле должно принимать 'a@a.com' и отвергать 'aaa'.

self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': [u'Enter a valid e-mail address.']})

Контекст-процессор TestCase.settings() и декоратор TestCase.override_settings()
На время теста можно удобно переопределять определённые настройки прямо из коробки:
@override_settings(LOGIN_URL='/other/login/')
def test_login(self): 
    response = self.client.get('/sekrit/') 
    self.assertRedirects(response, '/other/login/?next=/sekrit/')

Ранее подобную задачу мы решали с помощью крайне полезного модуля mock, облегчающего monkey-patching и не только.

To be continued...
Завтра очередная порция, не переключайтесь.

9 марта 2012 г.

Новинки Django 1.4, day 2: Безопасность и формы

Продолжаем «неделю Джанго», начало в предыдущих заметках ORM-плюшки и Day 0. До релиза 1.4 пишем про новинки фреймворка. Сегодня в фокусе безопасность.

Обновлен механизм хэширования паролей
Теперь вместо SHA1, считающегося недостаточно надёжным, по-умолчанию используется более устойчивый к брутфорсу PBKDF2. Если выбор разработчиков Django вам не по нраву, можно настроить свой предпочитаемый тип хэширования в переменной PASSWORD_HASHERS, выбрав из уже имеющегося списка, либо написав свой собственный. Надо заметить, что пароли хранятся в том же формате, что и раньше, так что пользователям сбрасывать их не придётся. Более того, в момент аутентификации со старым типом хэша последний будет апгрейдиться до PBKDF2 автоматически.

На наш взгляд очень правильное и изящное с точки зрения обратной совместимости решение.

Защита от кликджекинга (clickjacking) 
Кликджекингом называют ситуацию, когда пользователь, совершая клик на специально сформированной странице злоумышленника, на самом деле кликает по ссылке на совершенно другом сайте. Для борьбы с таким видом уязвимости вебсайтов добавили middleware, выставлющую специальный заголовок, который в современных браузерах запретит открытие сайта в ифрейме на других сайтах.

Подробнее про кликджекинг в моей заметке «Боремся с clickjacking» и в доках джанги.

Улучшения в CSRF-защите и XSS-защите
Добавлена поддержка CSRF-защиты для PUT- и DELETE- запросов, что облегчает работу с REST-вьюхами. Теперь можно настраивать путь CSRF-куки а также передавать её через HTTPS. Чтобы вид гарантированно посылал CSRF-куку появился декоратор ensure_csrf_cookie.
Подробнее про CSRF в целом

Для защиты сессионных кук от посягательств зловредного кода на javascript, оставленного на плохо защищенной от XSS странице, неплохо бы иметь дополнительную защиту. Теперь нельзя получить доступ к таким кукам через document.cookie. Это обратно несовместимое изменение, но оно вполне оправдано.

Подробнее в моей заметке «HttpOnly куки и с чем их едят».


Криптографическая подпись
Docs

В Django 1.4 появилось интересное API для криптографической подписи данных. Лучше абзаца слов скажут несколько строчек кода:
>>> signer = Signer()
>>> signer.sign('My string')
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'
>>> signer = Signer(salt='extra')
>>> signer.sign('My string')
'My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw'
>>> signer.unsign('My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw')
u'My string'

Можно подписывать как строчки, так и любые другие объекты, в качестве ключа используется SECRET_KEY из settings, опционально можно добавить соль. Для проверки того, когда было создано подписываемое значение есть готовый класс TimestampSigner.
Это низкоуровневое API хорошо подойдет для проверки целостности данных в hidden-полях, генерации урлов для восстановления пароля, других одноразовых урлов для доступа без авториазции и т.п.

Кроме того, Django открывает разработчикам и более высокоуровневое применение Signer: хранение данных сессии в куках. Гарантируется целостность данных в сессии за счёт подписи, но сами значения не шифруются и передаются открытым текстом. Стоит также учитывать ограничение на размер куки в 4кб и то, что размер куки влияет на то, как быстро открываются страницы вашего сайта. Зачем же такие ограничения? Для нового FormWizard'а.

Новый FormWizard
Docs

Внедрение криптографической подписи в Django связано с новой реализацией многошаговых форм. Теперь FormWizard основан на Class-based Views и поддерживает различные бэкенды для записи данных форм при переходе между шагами. Ранее хранившиеся в hidden-полях, теперь они могут быть сохранены как в сессии, так и в подписанных куках.

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

To be continued...
Завтра будет пост про новые фичи в тестировании.



8 марта 2012 г.

Новинки Django 1.4, day 1: ORM плюшки


Продолжение серии постов «Новинки Django 1.4».

Сегодня мы расскажем про те новинки, которые появились в компоненте ORM. Многие недолюбливают Django ORM за его простоту, которая мешает разработчикам составлять сложные SQL-запросы. С другой стороны нам трудно отрицать изящность API, превращающую большое число однотипных несложных запросов в читабельные QuerySet.

В Django 1.4 появилось сразу 3 новых метода:
  • bulk_create()
  • select_for_update()
  • prefetch_related()

Model.objects.bulk_create

Docs
Commit 16739

Полезная штука, позволяет вставлять в базу сразу несколько объектов в один запрос, например так:

Вместо N запросов:
Entry.objects.create(headline="Python 3.0 Released")
Entry.objects.create(headline="Python 3.1 Released")
...
Entry.objects.create(headline="Python 3.3 Planned") 

Теперь можно сделать тоже самое за один запрос:

Entry.objects.bulk_create([
    Entry(headline="Python 3.0 Released"),
    ...
    Entry(headline="Python 3.3 Planned") 
])

Плюс очевиден: это работает быстрей за счёт уменьшения количества запросов. Минусы в том, что функция save() для моделей не вызывается, сигналы pre_save и post_save не возбуждаются. Кроме того, метод не работает с мульти-табличным наследованием.

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



QuerySet.select_for_update()

Docs
Commit 16058

Реализация запросов вида SELECT ... FOR UPDATE для джанговского ORM. Запрос вида

entries = Entry.objects.select_for_update().filter(author=request.user)

создаст эксклюзивную блокировку на запись строк выборки до конца текущей транзакции. Если строки уже заблокированы другой транзакцией, запрос будет ждать её завершения, чтобы получить свою блокировку.  Чтобы избежать этого поведения, можно использовать необязательный атрибут nowait=True, который либо тут же без ожидания создаст блокировку, либо вызовет DatabaseError, если это невозможно.

Будьте внимательны, аргумент nowait не поддежривается бэкендом MySQL и вызовет всё тот же DatabaseError.

Функциональность будет полезна тем, кто желает создавать гарантированные row locks для изменения записей в базе данных в рамках транзакции, например, при обсчёте биллинга, увеличении счётчиков и т.п.

Реализация SELECT ... FOR UPDATE в PostgreSQL
Реализация SELECT ... FOR UPDATE в MySQL


QuerySet.prefetch_related

Docs
Commit 16930

Наверное, самая полезная фича сегодняшнего обзора. Она помогает радикально сократить число запросов, создаваемых через ORM без использования всяческих костылей (на DjangoCon Europe 2011 предлагались решения типа djanngo-unjoinify и django-queryset-transform).

Обычно для сокращения числа запросов используется метод .select_related(), который добавляет к запросу необходимые JOIN'ы. Несмотря на все его плюсы (указание глубины связей, а также полей, которые необходимо достать), этого явно недостаточно. select_related работает только со связями типа 1-M и 1-1 (ForeignKey и OnetoOne) и не поддерживает M-M. Данный пробел заполняет новый prefetch_related, который делает JOIN не в SQL, а на уровне питон-кода, добавляя по одному запросу на каждую связанную сущность.

Пример оптимизации из документации

#models.py
class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
   name = models.CharField(max_length=50)
   toppings = models.ManyToManyField(Topping)

def __unicode__(self):
   return u"%s (%s)" % (self.name, u", ".join([topping.name
            for topping in self.toppings.all()]))

#views.py
def show_me_some_pizzas():
    render_to_response(‘template.html’, {‘objects’:Pizza.objects.all()})


Выводя в шаблоне {{ pizza }} из вычисленного QuerySet, мы получим по дополнительному запросу на каждую пиццу, что совсем не круто (для 20 пицц в БД выходит 1+20=21 запрос). На помощь приходит prefetch_related:

#views.py
def show_me_some_pizzas_fixed():
render_to_response(‘template.html’, {‘objects’:Pizza.objects.all().prefetch_related('toppings')})


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

Функциональность prefetch_related этим не ограничивается, можно делать “псевдо-джойны” с птичьей нотацией:

Restaurant.objects.prefetch_related('best_pizza__toppings')

и даже совмещать их с настоящими джойнами через select_related

Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')


Более подробно читайте в доках prefetch_related


To be continued...
Завтра будет продложение про безопасность и формы

7 марта 2012 г.

Новинки Django 1.4, day 0

На этой неделе 5 марта вышел первый релиз-кандидат Django 1.4. С конца декабря, когда вышла альфа-версия, новых фич не появилось, зато постоянно исправляются баги и продолжает улучшаться документация.

Changelog Django 1.4

Обещают выпуск полноценного релиза через неделю во время очередного PyCon. В преддверии этого ожидаемого события мы подготовили для вас серию постов о новой функциональности. Каждый день мы будем публиковать заметку с достаточно подробным (но без занудства) описанием изменений в любимом фреймворке.

Содержание серии


  1. ORM
  2. Безопасность и Формы
  3. Тестирование
  4. Админка
  5. Структура проекта (manage.py)
  6. Структура проекта (свои шаблоны)
  7. Шаблоны
  8. Таймзоны

Мы осветим только самое интересные на наш взгляд моменты, за полным списком обращайтесь к release notes. Особенно советуем обратить внимание на Backwards incompatible changes и Features deprecated in 1.4. Они описаны достаточно хорошо, читайте внимательно.

Поддержка Python

Начиная с Django 1.4, разработчики отказываются от поддержки python 2.4 (который вышел более 7 лет назад), давно пора было это сделать. После релиза ожидается, что начнутся работы по внедрению поддержки Python 3, на данный момент существует только неофициальный экспериментальный бранч транка, который проходит большинство тестов как на 2.7.2 так и 3.2.2 (но не все). Обещано озвучить планы по выпуску Django 1.5 и поддержке python 3 в скором времени.
Обновление
Осенью планируется релиз 1.5 с поддержкой python 2.6 - 3.3, рассказали девелоперы на PyCon 2012.

Разработчики Django убеждены, что поддержка python 3 должна быть реализована без ущерба поддержки второй версии питона и на той же codebase, то есть быть как можно более обратно совместимой.

Надо заметить, что данную задачу во многом упростит недавно принятый PEP 414 “Explicit Unicode Literal for Python 3.3, возвращающий в питон явно обозначенные юникодные строки. Рекомендуем пост Армина с размышлениями на тему развития python 3.



To be continued...

Следите за обновлениями в блоге и за нами в твитере @futurecolors

2 марта 2012 г.

Moscow Django Meetup #1



1 марта в здании Высшей Школы Экономики на Покровском бульваре прошла первая встреча разработчиков на Django.

Часть нашей команды решила отправиться зрителями на это без преувеличения знаковое событие (в Москве до этого времени не было юзергруп, которые существуют в Европе и Америке).

Группа Moscow Django в Facebook


Темы

На встречу зарегистрировано 52 человека, пришла примерно половина. Было представлено 3 доклада:

  • Журнальная вёрстка на Django (слайды)
  • Сила ваших кончиков пальцев (слайды)
  • Миграция баз данных на South (слайды)
Слайды презентаций уже доступны, а скоро обещали выложить и запись видео, как только оно появится, обновим пост видео не будет из-за технического сбоя при записи.

Журнальная вёрстка на Django от Алексея Дубкова

Доклад был посвящён проблеме всех WYSIWYG’ов, а именно, их примитивности в форматировании наполнения сайтов. Алексей предложил вариант построения админки проекта, которая по задумке автора позволяет получить на сайте вёрстку контента как в журнале, то есть красивую и сложную.
В основе идеи - формирование страницы из блоков, каждый из которых представляет собой инстанс некоторой модели. Эти блоки подключаются через стандартную инлайн-модель к форме основного материала в админке. При публикации материала каждый блок рендерится по шаблону, соответствующему его типу, полученный HTML собирается в результирующий и сохраняется в модели основной сущности.
При обсуждении этого доклада много говорили об админке и её несовершенстве, в том числе о сложности обучения контент-мастеров работе с такими сложными и неудобными интерфейсами, как тот, который был представлен в докладе.

Сила ваших кончиков пальцев от Владимира Епифанова

Владимир рассказывал о важности использования консоли и делился опытом использования нескольких командных оболочек, таких как: sh, bash, zsh. Всё началось с описания привычных даже не юниксоидам команд и их ключей, а закончилось введением в sed, awk. Далее были представлены алиасы, сокращения и трюки для часто используемых паттернов. Обязательно взгляните на презентацию, можете найти для себя много полезного.

Миграция баз данных на South от Николая Ходова

Официальную часть встречи завершила презентация про незаменимый инструмент в «контроле версий» схем баз данных - South.  На комплексном примере было показано, как производить миграции структуры БД и миграции данных. Неплохое введение для новичков, чтобы начать погружение в тему миграций, которую Django пока что обходит стороной. В обсуждении доклада затронули более тонкие моменты, а именно нюансы использования South при коллективной разработке.

Django Drinkup

После завершения официальной части желающие переместились в заведение под названием «Пилзнер. Чешская пивная», где и продолжилось общение в неформальной обстановке. Как ни странно, компанию из оставшихся 12 человек без проблем усадили за один стол. Хорошо посидели в общем!

Special thanks

Отдельное спасибо организаторам: Валентину Домбровскому, Михаилу Корнееву и Виталию Коробкину. Надеемся их замечательное начинение будет иметь отличное продолжение и позволит сформироваться настоящему коммьюнити и, судя по группе на FB, это уже началось.


Следующая встреча разработчиков 5 апреля.


Артём Голиков
Илья Барышев
Виталий Олевинский