Когда ваше джанговские приложение/проект обрастает кодом всё больше и больше, то встает вопрос как максимально удобно организовать файловую структуру. И хотя Джанга не сильно капризна и требовательна к структуре модулей/пакетов, но всё-таки не всегда разработчик может себе позволить вольности. Джанга всё-таки ожидает, что какие-то части приложения будут лежать в определенных местах. Это относится к моделям, тестам, шаблонным тегам, определениям админки и т.п.
Из-за этого кстати и разработчик сторонних приложений ожидают, что ваш проект будет выглядеть так, а не иначе, поэтому каким-то образом на это закладываются.
Но поскольку мы имеем дело с очень гибким инструментов в лице питона и Джанги, то можем в большинстве ситуаций позволить себе обойти эти ограничения.
models.py
Наверно самая частая проблема - это разделение слишком большого файла models.py на более мелкие, атомарные, отвечающий за одну модель модули. Об этом не редко спрашивают в различных форумах и рассылках.
На самом деле, задача эта не сложная, но при решении надо не забыть одну хитрость, чтобы всё заработало как надо.
Итак представим, что у вас есть большой и толстый файл models.py, в котором есть несколько моделей. Для примера возьмем предметную область блога - модели Post, Comment, Tag. Мы хотим чтобы каждая модель обитала в своем модуле ...
Итак, продолжаю переосмысливать прошлые свои советы и снипеты, которые в нынешних условиях можно реализовать более правильно и изящно.
Сейчас вот посмотрим на проблему добавления к list-view в админке своей "кнопки" с каким-то действием. Возвращаясь к старому посту про "быстрое удаление", можно придумать несколько вариантов реализации подобной концепции, но уже со свежей джангой. Вот они:
Для Django 1.0. Поскольку в 1.0 старая админка канула в лету, то reverse('django.contrib.admin.views.main.delete_stage') уже не работает. Но не страшно, код метода модели достаточно чуть-чуть изменить:
def remove(self):
from django.core.urlresolvers import reverse
from django.contrib import admin
return '<a href="%s" class="deletelink">Delete</a>'\
% reverse(admin.site.root,
args=("/".join([self.__class__._meta.app_label,
self.__class__._meta.object_name,
self.pk, 'delete']),)))
Это конечно при условии, что вы используете дефолтный админский сайт (объект admin.site), иначе root надо указать объекта используемого кастомного сайта.
Но лучше поступить по другому. Перенести этот метод в ModelAdmin класс, описывающий админку для данной модели, изменив его например так:
class EntryAdmin(admin.ModelAdmin):
#...
list_display = [..., 'remove_link', ...]
#...
def remove_link(self, entry):
from django.core.urlresolvers import reverse
return '<a href="%s" class="deletelink">Delete</a>'\
% reverse(self.admin_site.root,
args=("/".join([self.model._meta ...
Как вы догадались, я продолжаю тему денормализации и моей реализации композитных полей.
С момента прошлого поста я успел значительно улучшить базовый CompositionField и решить несколько концептуальных проблем.
Итак что же новое появилось:
- Сделал низкоуровневый
CF полноценным классом, который теперь удобно сабклассить и добавлять новый функционал
- Появилось место для интроспекции. Присоединение к хост модели стало более интеллектуальным из-за возможного отложенного присоединения.
- Чуть-чуть изменился интерфейс - параметр
commit теперь может быть задан для конкретного триггера. Это сугубо практическое изменение, которое помогло решить одну проблему с бесконечной рекурсией.
- По совету Вани Сагалаева добавил генерацию
freeze_FOO метода, который включает/выключает обработку сигналов. Полезно когда надо обработать какие-то данные скопом, а потом так же скопом пересчитать денормализованные поля.
Я грозился написать высокоуровневые обертки над CF чтобы облегчить использование и упростить конечный интерфейс. Сегодня я расскажу о первом сабклассе CF: ForeignAttributeField - поле которое отслеживает изменения некого внешнего поля в связанном объекте. Причем, поле может находится на любом уровне вложенности связи, что иногда очень удобно. Как я уже писал в прошлый раз - поля объектов, на которые непосредственно ссылается модель, так денормализовывать смыла мало. Проще использовать select_related. Но если заветный атрибут лежит глубже и для доступа к нему надо приджоинить, допустим, пять таблиц, то тут уже другой расклад и ...
Нет, я не про музыку решил написать. А про композицию данный, агрегацию если хотите.
В джанге на данный момент агрегации в ORM нет. Но как известно скоро должна появиться, а значит жизнь в очередной раз станет проще.
Зачем?
Но на много ли? Да, писать запросы с агрегацией станет проще. Но в большинстве случаешь выполнять запрос для сервера легче не станет. Вот ту на помощь приходит техника денормализации.
Денормализация - это добавления избыточности данных для увеличения производительности чтения данный. Обычно чтение данных требуется гораздо чаще чем их запись, а значит на запись в принципе можно потратить чуть больше времени, за-то потом много раз сэкономить на выборке. Агрегацию я привел в качестве, наверно, самого популярного источника данных для денормализации, но ею конечно не ограничивается применение денормализации. Суть в том, что лучше что-то тяжелое посчитать при записи и сохранить, чем каждый раз при чтении пересчитывать заново.
Наверно многие из вас в своих проектах писали код наподобие такого, тем более, если писали "свой блог движок":
class Post(models.Model):
comment_count = models.PositiveIntegerField(default=0)
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments")
def save(self):
super(Comment, self).save()
self.post.comment_count = self.post.comments.count()
def delete(self):
super(Comment, self).delete ...
За проектом StackOverflow я наблюдал уже достаточно давно. Слушал подкасты о процессе разработки и ждал когда же увидит свет этот новый сервис. Гений его авторов позволил сделать грамотный ресурс для поиска ответов на разные программистские вопросы.
Для себя я сразу отметил два тега за которыми можно последить - python и django. Там среди кучи достаточно банальных вопросов попадаются и те, что из разряда - "я бы тоже не прочь почитать ответы". И пока, даже сообщество не до конца сформировалось, всё равно есть что почитать.
Так что всем рекомендую. Тем более, иной раз можно и самим кое-где свою точку зрения выразить. Я надеюсь что социальная часть сервиса себя не дискредитирует и получится действительно интересное сообщество с грамотными участниками.