2009-07-08 2 views
14

Я разрабатываю простое веб-приложение, и имеет смысл хранить некоторые денормализованные данные.Лучший способ денормализации данных в Django?

Представьте себе платформу для ведения блогов, которая отслеживает комментарии, а в модели BlogEntry есть поле CommentCount, которое я хотел бы обновлять.

Один из способов сделать это - использовать сигналы Django.

Другим способом сделать это было бы связать крючки непосредственно в моем коде, который создает и уничтожает объекты Comment для синхронного вызова некоторых методов в BlogEntry для увеличения/уменьшения количества комментариев.

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

Каков стандартный шаблон проектирования для денормализации в Django? На практике вам также приходится писать проверки целостности и фиксаторы данных в случае ошибок?

ответ

17

У вас есть менеджеры в Django.

Используйте настраиваемый менеджер для создания и поддержки отношений FK.

Менеджер может обновлять подсчеты по мере обновления наборов детей.

Если вы не хотите создавать специализированные менеджеры, просто используйте метод save. Все, что вы хотите сделать для денормализации подсчетов и сумм, можно сделать в save.

Вам не нужны сигналы. Просто протяните save.

+0

Отличный совет, вот что я сделал – kender

+0

Я тоже принимаю этот подход, пока у меня не было проблем. – Prairiedogg

+4

Знаете ли вы о хороших примерах этого стиля? Я поражен тем, что в документации Django (или в Django Book) не упоминаются подходы к денормализации вообще ... – slacy

-1

Почему бы не просто получить набор комментариев, и найти число элементов, используя метод count():

count = blog_entry.comment_set.count() 

Затем вы можете передать, что в шаблон.

Или, альтернатива, в самом шаблоне, вы можете сделать:

{{ blog_entry.comment_set.count }} 

, чтобы получить количество комментариев.

+0

Каждый раз, когда я вызываю count(), он будет делать «SELECT count (1) from Comment where ...», что в конечном итоге вызовет проблемы с производительностью при большом количестве комментариев. – slacy

+1

Сколько людей оставляют комментарии в своем блоге? – mipadi

4

Первый подход (сигналы) имеет преимущество для ослабления связи между моделями.
Однако, сигналы как-то сложнее поддерживать, потому что зависимости менее явные (по крайней мере, на мой взгляд).
Если правильность подсчета комментариев не так важна, вы также можете подумать о задании cron, которое будет обновлять его каждые n минут.

Однако, независимо от решения, денормализация затруднит техническое обслуживание; по этой причине я бы постарался избежать этого как можно больше, разрешая вместо этого использовать кеши или другие методы - например, использование with comments.count as cnt в шаблонах может значительно повысить производительность.
Тогда, если все остальное не удастся, и только в этом случае подумайте о том, какой может быть лучший подход для конкретной проблемы.

+0

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

+0

Кэширование будет иметь все проблемы обслуживания денормализации, т. Е. Поддерживать актуальность кэша, при необходимости аннулируя кэшированные данные. Хуже того, для этого вам не пригодится устройство Django ORM. Мое голосование было бы за django-denorm, как предложил @gorsky - он заботится обо всех проблемах обслуживания для вас, если у вас есть один из случаев использования денормализации, который он охватывает. – Anentropic

9

Я нашел django-denorm быть полезной. Он использует триггеры уровня базы данных вместо сигналов, но, насколько я знаю, существует также ветвь, основанная на другом подходе.

+0

+1 для django-denorm вместо ручного взлома ваших собственных сигналов и переопределенных методов, это отличная и простая система. – Anentropic

+0

Я изучил исходный код django-denorm. Я не вижу крючки для удаления операций ... Знаете ли вы, управляются ли они? Также мне кажется, что триггеры базы данных не используются, но это неплохо. Обычная таблица обновляется методами post-save в полях модели. –

1

Django предлагает отличную и эффективную (хотя и не очень известную) альтернативу счетчик денормализации.

Он сохранит ваши многочисленные строки кода, и это очень медленно, так как вы получаете счет в одном и том же запросе SQL.

Я полагаю, у вас есть эти классы:

class BlogEntry(models.Model): 
    title = models.CharField() 
    ... 


class Comment(models.Model): 
    body = models.TextField() 
    blog_entry = models.ForeignKey(BlogEntry) 

В вашем views.py используйте annotations:

from django.db.models import Count 

def blog_entry_list(Request): 
    blog_entries = BlogEntry.objects.annotate(count=Count('comment_set')).all() 
    ... 

И вы будете иметь дополнительное поле на каждый BlogEntry, который содержит счетчик комментариев, плюс остальные поля BlobEntry.

Вы можете использовать это дополнительное поле в шаблонах тоже:

{% for blog_entry in blog_entries %} 
    {{ blog_entry.title }} has {{ blog_entry.count }} comments! 
{% endfor %} 

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