I have a situation something like this (the actual code is bound up in a template, and omitted for brevity).
threads = Thread.objects.all()
for thread in threads:
print(thread.comments.count())
print(thread.upvotes.count())
I've managed to considerably reduce the total number of queries using Django's awesome prefetch_related
method.
threads = Thread.objects.prefetch_related('comments').prefetch_related('upvotes')
However I'm wondering if this situation could be further optimized. From what I understand prefetch_related
retrieves all of the data associated with the related models. Seeing as I only care about the amount of related models, and not about the models themselves, it seems like this query could be optimized further so that it doesn't retrieve a bunch of unnecessary data. Is there a way to do this in Django without dropping down to raw SQL?
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it.
Use Django's count() QuerySet method — simply append count() to the end of the appropriate QuerySet. Generate an aggregate over the QuerySet — Aggregation is when you "retrieve values that are derived by summarizing or aggregating a collection of objects." Ref: Django Aggregation Documentation.
In Django, select_related and prefetch_related are designed to stop the deluge of database queries that are caused by accessing related objects. In this article, we will see how it reduces the number of queries and make the program much faster.
The values_list() method allows you to return only the columns that you specify.
You're right, it's wasteful to fetch all that data from the database if all you want to do is get the count. I suggest annotation:
threads = (Thread.objects.annotate(Count('comments', distinct=True))
.annotate(Count('upvotes', distinct=True)))
for thread in threads:
print(thread.comments__count)
print(thread.upvotes__count)
See the annotation documentation for more information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With