我正在开发一个简单的Web应用程序,存储一些非规范化数据很有意义。
想象一个跟踪评论的博客平台,BlogEntry模型有一个“CommentCount”字段,我想跟上它。
这样做的一种方法是使用Django信号。
另一种方法是将钩子直接放在我的代码中,该代码创建和销毁Comment对象,以同步调用BlogEntry上的某些方法来增加/减少注释计数。
我想还有其他pythonic方法可以通过装饰器或其他巫术来实现这一点。
Django中反规范化的标准设计模式是什么?实际上,如果出现错误,您还必须编写一致性检查程序和数据修复程序吗?
答案 0 :(得分:18)
你有Django的经理。
使用自定义管理器来创建和维护FK关系。
管理员可以在更新子集时更新计数。
如果您不想制作自定义管理员,只需扩展save
方法即可。您想要对计数和总和进行非规范化处理的所有操作都可以在save
中完成。
您不需要信号。只需展开save
。
答案 1 :(得分:10)
我发现django-denorm很有用。它使用数据库级触发器而不是信号,但据我所知,还有基于不同方法的分支。
答案 2 :(得分:5)
第一种方法(信号)具有消除模型之间耦合的优点 然而,信号在某种程度上更难以维护,因为依赖性不太明确(至少在我看来) 如果评论计数的正确性不是那么重要,您还可以考虑一个每隔 n 分钟更新它的cron作业。
然而,无论解决方案如何,非正规化都会使维护更加困难;出于这个原因,我会尝试尽可能避免,而不是使用缓存或其他技术 - 例如,在模板中使用with comments.count as cnt
可以提高性能。<登记/>
然后,如果其他所有方法都失败了,只有在这种情况下,请考虑哪些方法可能是针对特定问题的最佳方法。
答案 3 :(得分:2)
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 %}
这不仅可以节省编码和维护时间,而且非常有效(查询只需要更长的时间来执行)。
答案 4 :(得分:-2)
为什么不使用count()
方法获取评论集,并找到元素数量:
count = blog_entry.comment_set.count()
然后您可以将其传递到模板中。
或者,或者,在模板本身中,您可以执行以下操作:
{{ blog_entry.comment_set.count }}
获取评论数量。