PyCharm бесплатно

26 сентября 2013

Вчера пришла новостная рассылка от JetBrains, в которой говорится о том, что теперь есть бесплатная версия PyCharm — Community Edition. Я сам уже три года как пользуюсь Professional Edition, и это замечательный продукт. А для Java я пользуюсь IntelliJ IDEA :) Очень рекомендую тем, кто пишет на Python, и еще не знаком с PyCharm, попробовать ее. Есть встроенная поддержка Django, virtualenv, Git/HG, тестирования и покрытия кода тестами.

Простое профилирование Django приложений

23 июня 2012

Оказывается, профилировать Django приложения очень просто. Для того, чтобы посмотреть SQL запросы, есть замечательный Django Debug Toolbar, а для классического профилирования времени/вызовов есть вот такой рецепт:

  1. Добавляем в requirements.txt django-extensions==0.9
  2. Ставим kcachegrind через порты: sudo port install kcachegrind
  3. Запускаем приложение: ./manage.py runprofileserver --kcachegrind --prof-path=/tmp/my-profile-data
  4. Вызываем интересующие нас view
  5. Запускаем X11, потом kcachegrind и скармливаем ему лог.

Встроенный cProfile мне показался не слишком удобным.

Django + PyPy + MySQL

4 мая 2012

Давно уже мои товарищи хвалят заоблачные скорости PyPy, но без работы с базами данных можно было только облизываться и мечтательно закатывать глаза, представляя рост производительности сайтов. Сегодня получилось подружить его с MySQL, так что появился отличный шанс проверить двойного питона с турбонаддувом в деле.

This is how I’ve managed to get PyPy working with MySQL:

  1. Download PyPy to some folder (I used /usr/local/pypy-1.8)
  2. Create a symlink in /usr/local/bin/ : ln -s /usr/local/pypy-1.8/bin/pypy pypy
  3. Make virtualenv with pypy as python: mkvirtualenv mysite —no-site-packages -p pypy
  4. Activate virtual env, install Django via pip
  5. Tricky part starts: download sources of MySQL-python
  6. Unpack it somethere in your virtualenv. Unfortunately you cannot use pip to install it. Go to this folder.
  7. You need to apply this patch, actually you need to patch only 2 files: converters.py and _mysql.c. Line numbers may be a bit different, this is Ok.
  8. After applying changes install MySQL-python via: python setup.py install
  9. Tricky part ends: try to work with your apps now.

Facebook iframe-приложения и Django CSRF

3 сентября 2011

Первое, что видят начинающие разработчики iframe-приложений для Facebook при обращении к их canvas view, — сообщение об ошибке CSRF. Связано это с тем, что при запуске iframe-приложения Facebook автоматически выполняет на canvas URL POST-запрос с информацией о текущем пользователе. Странно было бы ожидать в нем правильного CSRF-token. Обычной практикой является полный отказ от CSRF для Facebook. Другой вариант — это написание своих CSRF-токенов и их ручная проверка. Но небольшое исследование показало, что вполне можно пользоваться стандартным механизмом Django, если научиться проверять CSRF не всегда, а только когда это необходимо. А точнее, проверять CSRF стоит лишь в том случае, когда в POST-запросе нет корректного signed_request с access_token — его наличие недвусмысленно говорит нам о том, что POST-запрос пришел от Facebook. Вот как это решилось в нашем случае:

# Description for enlgish-speaking users:
# Easy and standard way to manage CSRF when developing Django applications for Facebook
from django.views.decorators.csrf import csrf_view_exempt
from django.middleware.csrf import CsrfViewMiddleware

# Function to check CSRF on demand (use {% csrf_token %} in your forms as usual)
def facebook_csrf_check(request):
    return CsrfViewMiddleware().process_view(request, facebook_csrf_check, None, None) == None

Функция facebook_csrf_check, собственно, является ручной проверкой на правильность CSRF. Вы можете вызывать ее при необходимости. Автоматическая проверка отключается декоратором csrf_view_exempt. Например:

# Your canvas view
@csrf_view_exempt
def facebook_canvas(request):

    if is_valid_access_token(request): # check whether a correct access_token presents
        ...

    print 'CSRF ' + str(facebook_csrf_check(request)) # facebook_csrf_check == True means CSRF is OK

facebook_csrf_check == True означает, что с csrf все в порядке.

Code snippet.

Remember Me на Django

22 февраля 2011

Недавно возникла необходимость сделать простую вещь – функциональность «запомнить меня». Требования простые: при установленном флажке «запомнить» пользователь считается прошедшим авторизацию и не должен вводить пароль еще раз. Выход из системы в этом случае производится при нажатии кнопки/ссылки «выйти».

При попытке найти что-то готовое результат был курьезный: кто-то решает это путем установки времени истечения сессии в 2036–2039 годах, другие примеры просто неправильные (по всей видимости, написаны под старые версии Django). Пришлось писать решение самому.

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

Я решил задачу, написав очень простой и понятный middleware:

from django.conf import settings
from datetime import timedelta, date
class KeepLoggedInMiddleware(object):
    def process_request(self, request):
        if not request.user.is_authenticated() or not settings.KEEP_LOGGED_KEY in request.session:
            return
        if request.session[settings.KEEP_LOGGED_KEY] != date.today():
            request.session.set_expiry(timedelta(days=settings.KEEP_LOGGED_DURATION))
            request.session[settings.KEEP_LOGGED_KEY] = date.today()
        return

Чем удобен middleware: не требуется никакой дополнительный код где-то еще. Для работы в Settings нужно сделать следующее:

  1. Добавить имя_модуля. KeepLoggedInMiddleware в MIDDLEWARE_CLASSES (я поставил его последним, чтобы уже работал middleware сессий)
  2. Добавить настройки:
# Keep me logged settings
KEEP_LOGGED_KEY = 'keep_me_logged'
KEEP_LOGGED_DURATION = 365 # in days

KEEP_LOGGED_KEY – имя ключа с данными в сессии пользователя, KEEP_LOGGED_DURATION – срок в днях, который вы бы хотели помнить пользователя. Одного года, на мой взгляд, более чем достаточно.
Затем в функции обработки формы авторизации, если флажок «запомнить меня» включен, вы делаете примерно следующее:

   form = LoginForm(request.POST)
    if form.is_valid():

            ....

            if form.remember:
                request.session[settings.KEEP_LOGGED_KEY] = True

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

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

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

Remember Me by SylarNight

Django: полиморфные связи между базами данных

9 ноября 2010

Внезапно Винни-Пух остановился и нагнулся к земле.
— В чём дело? — спросил Пятачок.
— Очень странная вещь,- сказал медвежонок.- Теперь тут, кажется, стало два зверя. Вот к этому — Неизвестно Кому — подошёл другой — Неизвестно Кто, и они теперь гуляют вдвоём.

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

Проблема

Изначально в проекте, помимо прочих, было две таблицы: одна таблица, скажем, Статьи и другая таблица, скажем, Сообщения. Сообщение могло быть связано с какой-то Статьей, чтобы было понятно, о чем идет речь. В новой версии проекта было принято решение добавить еще одну таблицу – Продукты и расширить таблицу Сообщений так, чтобы можно было писать сообщения и про Продукты. То есть вместо простого Foreign Key из одной понятной таблицы нужно было сделать не то Conditional Foreign Key, не то Polymorphic Foreign Key на Неизвестно Какую Таблицу. Нужно заметить, что сообщение может относиться только к чему-то одному, оно не может быть одновременно про Статью и Продукт.
Читать дальше…