Лучший способ денормализации данных в Django?
Я разрабатываю простое веб-приложение, и имеет смысл хранить некоторые денормализованные данные.
Представьте себе платформу для ведения блогов, которая отслеживает комментарии, а в модели BlogEntry есть поле "CommentCount", которое я хотел бы поддерживать в актуальном состоянии.
Один из способов сделать это - использовать сигналы Django.
Другим способом сделать это было бы привязать крючки непосредственно в моем коде, который создает и уничтожает объекты Comment для синхронного вызова некоторых методов в BlogEntry для увеличения/уменьшения количества комментариев.
Я полагаю, что есть другие способы питонизации этого с декораторами или другим вуду.
Каков стандартный шаблон проектирования для денормализации в Django? На практике вам также приходится писать проверки целостности и фиксаторы данных в случае ошибок?
Ответы
Ответ 1
У вас есть менеджеры в Django.
Используйте настраиваемый менеджер для создания и поддержки отношений FK.
Менеджер может обновлять счетчики по мере обновления наборов дочерних элементов.
Если вы не хотите создавать настраиваемые менеджеры, просто расширяйте метод save
. Все, что вы хотите сделать для денормализации подсчетов и сумм, можно сделать в save
.
Вам не нужны сигналы. Просто растяните save
.
Ответ 2
Я нашел django-denorm, чтобы быть полезным. Он использует триггеры уровня базы данных вместо сигналов, но, насколько я знаю, существует также ветвь, основанная на другом подходе.
Ответ 3
Первый подход (сигналы) имеет преимущество для ослабления связи между моделями.
Однако, сигналы как-то более сложно поддерживать, потому что зависимости менее явные (по крайней мере, на мой взгляд).
Если правильность подсчета комментариев не так важна, вы также можете подумать о задании cron, которое будет обновлять его каждые n минут.
Однако, независимо от решения, денормализация затруднит обслуживание; по этой причине я постараюсь максимально избежать этого, разрешая вместо этого использовать кеши или другие методы - например, использование with comments.count as cnt
в шаблонах может значительно повысить производительность.
Затем, если все остальное терпит неудачу и только в этом случае, подумайте о том, что может быть лучшим подходом к конкретной проблеме.
Ответ 4
Django предлагает отличную и эффективную (хотя и не очень известную) альтернативу денормализации счетчика.
Он сохранит ваши многочисленные строки кода, и он будет очень медленным, так как вы получите счетчик в том же запросе SQL.
Я предполагаю, что у вас есть эти классы:
class BlogEntry(models.Model):
title = models.CharField()
...
class Comment(models.Model):
body = models.TextField()
blog_entry = models.ForeignKey(BlogEntry)
В вашем view.py используйте аннотации:
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 %}
Это позволит не только сохранить время кодирования и обслуживания, но и эффективно (запрос выполняется только немного дольше).
Ответ 5
Почему бы просто не получить набор комментариев и найти количество элементов, используя метод count()
:
count = blog_entry.comment_set.count()
Затем вы можете передать это в свой шаблон.
Или, альтернативно, в самом шаблоне вы можете сделать:
{{ blog_entry.comment_set.count }}
чтобы получить количество комментариев.