<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru-RU"><title>gearheart.org.ua</title><link href="http://gearheart.org.ua/blog/" rel="alternate"></link><link href="http://gearheart.org.ua/blog/latest/feed/" rel="self"></link><id>http://gearheart.org.ua/blog/</id><updated>2015-02-14T04:37:08Z</updated><entry><title>Аяксовые блоки в джанго</title><link href="http://gearheart.org.ua/blog/ajax-blocks-django/" rel="alternate"></link><id>http://gearheart.org.ua/blog/ajax-blocks-django/</id><summary type="html">&lt;p&gt;Часто приходится писать блоки с разбивкой по страницам или фильтрацией, такие, что выводятся сначала на страницу при помощи шаблонного тега, а потом обновляются аяксом.&lt;/p&gt;
&lt;p&gt;Для этого я использовал простую конструкция - inclusion tag, который создает контекст для рендера и view, который вынимал аргументы из запроса и запускал тот же inclusion tag. Получалось, что для одного такого блока приходилось (помимо шаблона) редактировать три файла - тег, обертка-view, объявление в urls.&lt;/p&gt;
&lt;p&gt;Мне это надоело и я написал небольшой декоратор, который позволяет автоматизировать весь этот процесс.&lt;/p&gt;</summary></entry><entry><title>Инвалидация кэша для css спрайтов</title><link href="http://gearheart.org.ua/blog/css-sprites-cache-invalidation/" rel="alternate"></link><id>http://gearheart.org.ua/blog/css-sprites-cache-invalidation/</id><summary type="html">&lt;p&gt;При использовании css-спрайтов нужно заставить браузер кэшировать эти изображения на как можно более долгий срок. С другой стороны важно заставить браузер перегружать изображение как только оно изменилось. Это особенно заметно когда все иконки сайта склеены в одно изображение - при использовании устаревшего спрайта весь сайт выглядит криво.&lt;/p&gt;
&lt;p&gt;Для решения этой задачи я написал небольшой велосипед, который добавляет к ссылкам на изображения их хеш:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;background-image: url(images/icons.png?a3844c660);&lt;/code&gt;&lt;/p&gt;</summary></entry><entry><title>Создание css спрайтов</title><link href="http://gearheart.org.ua/blog/css-sprites-generation/" rel="alternate"></link><id>http://gearheart.org.ua/blog/css-sprites-generation/</id><summary type="html">&lt;p&gt;Написал небольшую библиотеку для создания css-спрайтов. Склеивает изображения из заданной папки в одно и создает соответсвующий css.&lt;/p&gt;</summary></entry><entry><title>Тестирование авторизации в Django</title><link href="http://gearheart.org.ua/blog/testing-authorization-django/" rel="alternate"></link><id>http://gearheart.org.ua/blog/testing-authorization-django/</id><summary type="html">&lt;p&gt;Чтобы проверить авторизован ли пользователь в тестах, можно использовать такой код:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from django.contrib.auth import get_user

class MyTestCase(TestCase):
    def test_login(self):
        self.assertFalse(get_user(self.client).is_authenticated())
        self.client.login(username='fred', password='secret')
        self.assertTrue(get_user(self.client).is_authenticated())
&lt;/code&gt;&lt;/pre&gt;</summary></entry><entry><title>Поиск символа в Emacs как в Vim</title><link href="http://gearheart.org.ua/blog/vim-search-char-in-emacs/" rel="alternate"></link><id>http://gearheart.org.ua/blog/vim-search-char-in-emacs/</id><summary type="html">&lt;p&gt;В виме есть команда поиска символа: f. После первого запуска ее можо повторять точкой с запятой.
Мне нравится перемещаться при помощи нее по строке - видишь, что надо перейти к скобке где-то в середине строки - f( и еще пару раз ; чтобы перейти к нужному месту.&lt;/p&gt;
&lt;p&gt;В емаксе такой команды нет, пришлось писать самому. Причем получилось даже сделать повторение при помощи ;&lt;/p&gt;</summary></entry><entry><title>Динамическое создание классов, QuerySetManager и use_for_related_fields</title><link href="http://gearheart.org.ua/blog/dynamic-class-generation/" rel="alternate"></link><id>http://gearheart.org.ua/blog/dynamic-class-generation/</id><summary type="html">&lt;p&gt;Как оказалось, не все знают, что классы в питоне можно создавать динамически, причем без метаклассов. Приведу пример.&lt;/p&gt;
&lt;p&gt;Мы уже научились использовать свой QuerySet для построения цепочек запросов:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Article.objects.old().public()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Теперь надо заставить это работать для связанных объектов:&lt;/p&gt;
&lt;p&gt;user.articles.old().public()&lt;/p&gt;
&lt;p&gt;Это делается при помощи &lt;a href="http://docs.djangoproject.com/en/dev/topics/db/managers/#controlling-automatic-manager-types"&gt;use_for_related_fields&lt;/a&gt;, но нужен небольшой трюк.&lt;/p&gt;</summary></entry><entry><title>OR и AND без django.db.models.Q</title><link href="http://gearheart.org.ua/blog/or-and-wo-django-db-models-Q/" rel="alternate"></link><id>http://gearheart.org.ua/blog/or-and-wo-django-db-models-Q/</id><summary type="html">&lt;p&gt;Только сейчас узнал, что для QuerySet определены методы &lt;code&gt;__or__&lt;/code&gt; и &lt;code&gt;__and__&lt;/code&gt;. Это значит, что для объединения или пересечания условий выборки можно делать, например:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;User.objects.filter(...) | User.objects.filter(...)
User.objects.filter(...) &amp;amp; User.objects.filter(...)
&lt;/code&gt;&lt;/pre&gt;</summary></entry><entry><title>Переопределение QuerySet</title><link href="http://gearheart.org.ua/blog/queryset-override/" rel="alternate"></link><id>http://gearheart.org.ua/blog/queryset-override/</id><summary type="html">&lt;p&gt;Как известно, менеджеры моделей в Django можно переопределять. Так можно
добавить удобные методы для фильтрации:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Article.objects.published()
Article.objects.old()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Но переопределение менеджера не позволяет использовать свои методы по очереди:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Article.objects.published().old()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В этой заметке я расскажу как реализуется такая функциональность.&lt;/p&gt;</summary></entry><entry><title>Twitter API, OAuth и декораторы</title><link href="http://gearheart.org.ua/blog/twitter-api-oauth-decorator/" rel="alternate"></link><id>http://gearheart.org.ua/blog/twitter-api-oauth-decorator/</id><summary type="html">&lt;p&gt;В текущем проекте появилась задача использовать API твиттера.
Для авторизации твиттер использует OAuth, который довольно муторный. Чтобы не
возиться с ним постоянно, я вынес всю авторизацию в декоратор, так что работа с
API выглядит так:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@twitter_api
def tweet_hello(request, api):
    api.update_status('hello')
    # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Декоратор проверят наличие ключа, если надо - производит авторизацию. Пользователь
перенаправляется на сайт твиттера, дает согласие, перенаправляется обратно и
продолжает работу с того же места. Если ключ уже есть - ничего не происходит,
просто запускается view.&lt;/p&gt;
&lt;p&gt;Удобно, что не нужно делать отдельной настройки твиттера в профиле пользователя.&lt;/p&gt;
&lt;p&gt;Код можно посмотреть в продолжении статьи.&lt;/p&gt;</summary></entry><entry><title>Ajax валидация форм</title><link href="http://gearheart.org.ua/blog/ajax-form-validation/" rel="alternate"></link><id>http://gearheart.org.ua/blog/ajax-form-validation/</id><summary type="html">&lt;p&gt;Возникла задача отправлять форму аяксом, разумеется с проверкой значений.
Очевидный способ решения - делать проверку на сервере и возвращать json с ошибками.&lt;/p&gt;
&lt;p&gt;Мне очень не нравилась перспектива писать отдельный &lt;code&gt;view&lt;/code&gt; для проверки формы и
 расставлять ошибки по документу яваскриптом.
Тем более, что уже есть готовый шаблон формы с ошибками, надо его использовать.&lt;/p&gt;
&lt;p&gt;В этой статье я расскажу, как решил для себя эту задачу.&lt;/p&gt;</summary></entry><entry><title>Переопределение настроек в settings_local</title><link href="http://gearheart.org.ua/blog/settings-override/" rel="alternate"></link><id>http://gearheart.org.ua/blog/settings-override/</id><summary type="html">&lt;p&gt;Для локальных настроек проекта я использую известный трюк с &lt;code&gt;settings_local&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try:
    from settings_local import *
except ImportError:
    pass
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Тоесть в файле &lt;code&gt;settings_local.py&lt;/code&gt; переопределяются настройки из &lt;code&gt;settings.py&lt;/code&gt;.
Мне было почему-то непонятно как можно свойства дополнить.
Например, добавить строку в &lt;code&gt;INSTALLED_APPS&lt;/code&gt;, не копируя весь список.&lt;/p&gt;
&lt;p&gt;Но вот вчера утром вдруг наконец-то дошло, что можно импортировать &lt;code&gt;settings&lt;/code&gt; в
&lt;code&gt;settings_local&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# settings_local.py

from settings import *

INSTALLED_APPS += (
    # ...
)
&lt;/code&gt;&lt;/pre&gt;</summary></entry><entry><title>Объединение нескольких view в Django</title><link href="http://gearheart.org.ua/blog/multiple-views-combination-django/" rel="alternate"></link><id>http://gearheart.org.ua/blog/multiple-views-combination-django/</id><summary type="html">&lt;p&gt;Следуя философии UNIX, каждая view выполняет только одну задачу.
Это хорошо, но иногда нужно объединить на одной странице логику нескольких view.
Отфильтровать, отсортировать, разбить по страницам. Или, например, добавить
комментарий прямо на странице товара.&lt;/p&gt;
&lt;p&gt;В этой статье я расскажу, как можно писать view, которые позволяют подобные
объединения.&lt;/p&gt;</summary></entry><entry><title>Бизнес-логика в моделях</title><link href="http://gearheart.org.ua/blog/business-logic-in-models/" rel="alternate"></link><id>http://gearheart.org.ua/blog/business-logic-in-models/</id><summary type="html">&lt;p&gt;В последнем моем проекте было очень много бизнес-логики. Потому пришлось как-то
структурировать работу с ней. В этой заметке я расскажу о паре приемов,
которые, возможно, не для всех очевидны.&lt;/p&gt;</summary></entry><entry><title>Абсолютные пути в модели </title><link href="http://gearheart.org.ua/blog/absolute-urls-in-models/" rel="alternate"></link><id>http://gearheart.org.ua/blog/absolute-urls-in-models/</id><summary type="html">&lt;p&gt;Все знают про &lt;code&gt;permalink&lt;/code&gt;, но используют его только для &lt;code&gt;get_absolute_url&lt;/code&gt;.
Я же предпочитаю задавать все относящиеся к объекту пути в модели:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Event(models.Model):
    # ...
    @models.permalink
    def edit_url(self):
        return ('event_edit', (self.pk, ))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Затем в шаблоне:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;a href="{{ event.edit_url }}"&amp;gt;Редактировать событие&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</summary></entry><entry><title>Профили пользователей с наследованием в Django</title><link href="http://gearheart.org.ua/blog/inherited-user-profiles-django/" rel="alternate"></link><id>http://gearheart.org.ua/blog/inherited-user-profiles-django/</id><summary type="html">&lt;p&gt;Профиль пользователя обычно хранится в одной модели и, если необходимо разделение
пользователей на типы, это делается простым текстовым полем &lt;code&gt;user_type&lt;/code&gt; или
каким-то подобным.&lt;/p&gt;
&lt;p&gt;Немного сложнее организовать такие типы пользователей, для каждого из которых нужно
хранить разные данные. Тоесть, нужны разные модели.&lt;/p&gt;
&lt;p&gt;В этой статье я расскажу каким способом решил такую задачу.&lt;/p&gt;</summary></entry></feed>