在Django中对数据进行非规范化的最佳方法?

时间:2009-07-08 22:41:04

标签: python mysql django

我正在开发一个简单的Web应用程序,存储一些非规范化数据很有意义。

想象一个跟踪评论的博客平台,BlogEntry模型有一个“CommentCount”字段,我想跟上它。

这样做的一种方法是使用Django信号。

另一种方法是将钩子直接放在我的代码中,该代码创建和销毁Comment对象,以同步调用BlogEntry上的某些方法来增加/减少注释计数。

我想还有其他pythonic方法可以通过装饰器或其他巫术来实现这一点。

Django中反规范化的标准设计模式是什么?实际上,如果出现错误,您还必须编写一致性检查程序和数据修复程序吗?

5 个答案:

答案 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 }}

获取评论数量。