我正在使用django comments frameworks。所有评论都由经过身份验证的用户发布。在评论附近,我正在使用{{ 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>
问题是django的评论查询不使用select_related()
,而对于100条评论我在数据库中获得了101次。
有没有办法让django评论框架一次性为每个评论选择用户资料?
答案 0 :(得分:10)
我测试了一个带有默认{% get_comment_list %}
标签的对象的100条评论,而django做了200条评论相关的查询以列出评论+用户+个人资料,因为......
Comment.__unicode__
存在,Comment.user
实际上会调用user_id
。 +1查询get_profile
+1查询哎哟!
我从~25ms的203个查询到~2ms的3个查询。
我会强烈建议使用相应的comment_list
调用自己构建QuerySet
select_related()
。如果经常使用它,请创建一个从其他视图调用的实用程序函数。
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'))
这不是我会轻易做的事情。还有其他方法可以解决这个具体问题,但你确实“一气呵成”。
将其放在INSTALLED_APPS
models.py
个文件中。我实际上有一个monkey_patch
应用程序用于修改django.contrib.auth.User.username
长度等等(这是最后的手段,不像这里)。
from django.contrib.comments.models import Comment
from django.contrib.comments.managers import CommentManager
class CommentManager(CommentManager):
def get_query_set(self):
return (super(CommentManager, self)
.get_query_set()
.select_related('user__profile'))
Comment.add_to_class('objects', CommentManager())
请注意,您的UserProfile
课程需要OneToOneField
到User
,related_name
等于您传递给select_related()
的课程。在我的例子中,它是profile
,你需要django 1.2+。我记得以前磕磕绊绊。
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
# example to use User.objects.select_related('profile')
答案 1 :(得分:4)
假设你有这样的设置:
class UserProfile(models.Model):
user = models.ForeignKey(User, related_name='profile')
...
您可以使用以下选择相关:Comments.objects.select_related('user__pk','user__profile__pk')
,这应该做你想要的。
您必须扩展评论框架。这非常简单。基本上,创建自己的评论应用程序。您可以查看django-threadedcomments获取灵感(实际上,在某些方面,它已经是一个更好的实现方式)。
这里可以插入django-threaded评论应用程序的代码,以确保它始终使用相关的选择(在models.py中):
class RelatedCommentManager(CommentManager):
def filter(self, *args, **kwargs):
return super(RelatedCommentManager, self).select_related('user__pk','user__profile__pk').filter(*args, **kwargs)
def exclude(self, *args, **kwargs):
return super(RelatedCommentManager, self).select_related('user__pk','user__profile__pk').exclude(*args, **kwargs)
def all(self)
return super(RelatedCommentManager, self).select_related('user__pk','user__profile__pk').all()
并替换
objects = CommentManager()
带
objects = RelatedCommentManager()
按照说明将threcomments集成到您的应用中。
然后,在模板中,我认为您必须引用.profile
而不是.get_profile
。
可能是Django会自动将其加入,因此只要get_profile
可用,.profile
就不会生成另一个数据库命中。
答案 2 :(得分:0)
在此示例中不能使用select_related(),因为User是配置文件的外键,反之亦然。 为了避免使用缓存(这可能是最佳选项),您可以使用外键创建Comment模型的代理模型。然后你可以写:
{{ comment.submit_date }} - {{ comment.user.profile.display_name }}