[Fixed]-Best way to denormalize data in Django?

17πŸ‘

βœ…

You have managers in Django.

Use a customized manager to do creates and maintain the FK relationships.

The manager can update the counts as the sets of children are updated.

If you don’t want to make customized managers, just extend the save method. Everything you want to do for denormalizing counts and sums can be done in save.

You don’t need signals. Just extend save.

πŸ‘€S.Lott

10πŸ‘

I found django-denorm to be useful. It uses database-level triggers instead of signals, but as far as I know, there is also branch based on different approach.

πŸ‘€gorsky

5πŸ‘

The first approach (signals) has the advantage to loose the coupling between models.
However, signals are somehow more difficult to maintain, because dependencies are less explicit (at least, in my opinion).
If the correctness of the comment count is not so important, you could also think of a cron job that will update it every n minutes.

However, no matter the solution, denormalizing will make maintenance more difficult; for this reason I would try to avoid it as much as possible, resolving instead to using caches or other techniques β€” for example, using with comments.count as cnt in templates may improve performance quite a lot.
Then, if everything else fails, and only in that case, think about what could be the best approach for the specific problem.

πŸ‘€rob

4πŸ‘

Django offers a great and efficient (though not very known) alternative to counter denormalization.

It will save your many lines of code and it’s really slow since you retrieve the count in the same SQL query.

I will suppose you have these classes:

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


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

In your views.py, use annotations:

from django.db.models import Count

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

And you will have an extra field per each BlogEntry, that contains the count of comments, plus the rest of fields of BlobEntry.

You can use this extra field in the templates too:

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

This will not only save you coding and maintenance time but it is really efficient (the query takes only a bit longer to be executed).

-1πŸ‘

Why not just get the set of comments, and find the number of elements, using the count() method:

count = blog_entry.comment_set.count()

Then you can pass that into your template.

Or, alternative, in the template itself, you can do:

{{ blog_entry.comment_set.count }}

to get the number of comments.

πŸ‘€mipadi

Leave a comment