Issue
I'm using django comments frameworks. All the comments are posted by authenticated users. Near the comment, I'm showing some user profile info using {{ comment.user.get_profile }}
{# custom comment list templates #}
<dl id="comments">
{% for comment in comment_list %}
<dt id="c{{ comment.id }}">
{{ comment.submit_date }} - {{ comment.user.get_profile.display_name }}
</dt>
<dd>
<p>{{ comment.comment }}</p>
</dd>
{% endfor %}
</dl>
Problem is that django's comment queries does not use select_related()
and for 100 comments I get 101 hit on the database.
Is there a way to make django comments framework to select user profile for each comment in one go?
Solution
I tested rendering 100 comments for an object with the default {% get_comment_list %}
tag and django did 200 comment related queries to list the comments + user + profile because...
Comment.__unicode__
actually callsComment.user
if auser_id
exists. +1 queryget_profile
+1 query
Ouch!
I went from 203 queries in ~25ms to 3 in ~2ms.
Populate comment_list yourself
I would highly suggest building the comment_list
QuerySet
yourself using the appropriate select_related()
calls. If it's used often, create a utility function called from your other views.
def get_comments_with_user_and_profile(obj):
content_type =ContentType.objects.get_for_model(obj)
return (Comment.objects
.filter(content_type=content_type, object_pk=obj.id)
.select_related('user__profile'))
If you want the entire framework to behave this way... You'll have to monkey patch.
It's not something I would do lightly. There are other ways around this specific problem but you did ask "in one go".
Put this somewhere in your INSTALLED_APPS
models.py
files. I actually have a monkey_patch
app for modifying django.contrib.auth.models.User.username
lengths and such (which is a last resort unlike here).
from django.contrib.comments.models import Comment
from django.contrib.comments.managers import CommentManager
class CommentManager(CommentManager):
def get_queryset(self):
return (super(CommentManager, self)
.get_queryset()
.select_related('user__profile'))
Comment.add_to_class('objects', CommentManager())
Gotchas with profiles and select_related()
Note that your UserProfile
class needs a OneToOneField
to User
with a related_name
equal to what you pass to select_related()
. In my example it's profile
and you need django 1.2+. I recall stumbling on that before.
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
# example to use User.objects.select_related('profile')
Answered By - Yuji 'Tomita' Tomita
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.