Часто приходится писать блоки с разбивкой по страницам или фильтрацией, такие, что выводятся сначала на страницу при помощи шаблонного тега, а потом обновляются аяксом.
Для этого я использовал простую конструкция - inclusion tag, который создает контекст для рендера и view, который вынимал аргументы из запроса и запускал тот же inclusion tag. Получалось, что для одного такого блока приходилось (помимо шаблона) редактировать три файла - тег, обертка-view, объявление в urls.
Мне это надоело и я написал небольшой декоратор, который позволяет автоматизировать весь этот процесс. →
При использовании css-спрайтов нужно заставить браузер кэшировать эти изображения на как можно более долгий срок. С другой стороны важно заставить браузер перегружать изображение как только оно изменилось. Это особенно заметно когда все иконки сайта склеены в одно изображение - при использовании устаревшего спрайта весь сайт выглядит криво.
Для решения этой задачи я написал небольшой велосипед, который добавляет к ссылкам на изображения их хеш:
background-image: url(images/icons.png?a3844c660);
→
Написал небольшую библиотеку для создания css-спрайтов. Склеивает изображения из заданной папки в одно и создает соответсвующий css. →
Чтобы проверить авторизован ли пользователь в тестах, можно использовать такой код:
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())
В виме есть команда поиска символа: f. После первого запуска ее можо повторять точкой с запятой. Мне нравится перемещаться при помощи нее по строке - видишь, что надо перейти к скобке где-то в середине строки - f( и еще пару раз ; чтобы перейти к нужному месту.
В емаксе такой команды нет, пришлось писать самому. Причем получилось даже сделать повторение при помощи ; →
Как оказалось, не все знают, что классы в питоне можно создавать динамически, причем без метаклассов. Приведу пример.
Мы уже научились использовать свой QuerySet для построения цепочек запросов:
Article.objects.old().public()
Теперь надо заставить это работать для связанных объектов:
user.articles.old().public()
Это делается при помощи use_for_related_fields, но нужен небольшой трюк. →
Только сейчас узнал, что для QuerySet определены методы __or__ и __and__. Это значит, что для объединения или пересечания условий выборки можно делать, например:
User.objects.filter(...) | User.objects.filter(...)
User.objects.filter(...) & User.objects.filter(...)
Как известно, менеджеры моделей в Django можно переопределять. Так можно добавить удобные методы для фильтрации:
Article.objects.published()
Article.objects.old()
Но переопределение менеджера не позволяет использовать свои методы по очереди:
Article.objects.published().old()
В этой заметке я расскажу как реализуется такая функциональность. →
В текущем проекте появилась задача использовать API твиттера. Для авторизации твиттер использует OAuth, который довольно муторный. Чтобы не возиться с ним постоянно, я вынес всю авторизацию в декоратор, так что работа с API выглядит так:
@twitter_api
def tweet_hello(request, api):
api.update_status('hello')
# ...
Декоратор проверят наличие ключа, если надо - производит авторизацию. Пользователь перенаправляется на сайт твиттера, дает согласие, перенаправляется обратно и продолжает работу с того же места. Если ключ уже есть - ничего не происходит, просто запускается view.
Удобно, что не нужно делать отдельной настройки твиттера в профиле пользователя.
Код можно посмотреть в продолжении статьи. →
Возникла задача отправлять форму аяксом, разумеется с проверкой значений. Очевидный способ решения - делать проверку на сервере и возвращать json с ошибками.
Мне очень не нравилась перспектива писать отдельный view для проверки формы и
расставлять ошибки по документу яваскриптом.
Тем более, что уже есть готовый шаблон формы с ошибками, надо его использовать.
В этой статье я расскажу, как решил для себя эту задачу. →
Для локальных настроек проекта я использую известный трюк с settings_local:
try:
from settings_local import *
except ImportError:
pass
Тоесть в файле settings_local.py переопределяются настройки из settings.py.
Мне было почему-то непонятно как можно свойства дополнить.
Например, добавить строку в INSTALLED_APPS, не копируя весь список.
Но вот вчера утром вдруг наконец-то дошло, что можно импортировать settings в
settings_local:
# settings_local.py
from settings import *
INSTALLED_APPS += (
# ...
)
Следуя философии UNIX, каждая view выполняет только одну задачу. Это хорошо, но иногда нужно объединить на одной странице логику нескольких view. Отфильтровать, отсортировать, разбить по страницам. Или, например, добавить комментарий прямо на странице товара.
В этой статье я расскажу, как можно писать view, которые позволяют подобные объединения. →
В последнем моем проекте было очень много бизнес-логики. Потому пришлось как-то структурировать работу с ней. В этой заметке я расскажу о паре приемов, которые, возможно, не для всех очевидны. →
Все знают про permalink, но используют его только для get_absolute_url.
Я же предпочитаю задавать все относящиеся к объекту пути в модели:
class Event(models.Model):
# ...
@models.permalink
def edit_url(self):
return ('event_edit', (self.pk, ))
Затем в шаблоне:
<a href="{{ event.edit_url }}">Редактировать событие</a>
Профиль пользователя обычно хранится в одной модели и, если необходимо разделение
пользователей на типы, это делается простым текстовым полем user_type или
каким-то подобным.
Немного сложнее организовать такие типы пользователей, для каждого из которых нужно хранить разные данные. Тоесть, нужны разные модели.
В этой статье я расскажу каким способом решил такую задачу. →