如何使 Django 注释在“用户”上使用 select_lated()场地?
我正在使用 django 注释框架。所有评论均由经过身份验证的用户发布。在评论附近,我使用 {{ 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_lated()
并且100 条评论我在数据库中得到了 101 条点击。
有没有一种方法可以让 django 评论框架一次性为每个评论选择用户配置文件?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我测试了使用默认
{% get_comment_list %}
标记为对象渲染 100 条评论,django 执行了 200 条评论相关查询来列出评论 + 用户 + 配置文件,因为...Comment.__unicode__<如果
user_id
存在,/code> 实际上会调用Comment.user
。 +1 查询get_profile
+1 查询哎呀!
我从约 25 毫秒内的 203 个查询减少到约 2 毫秒内的 3 个查询。
自己填充 comment_list
我强烈建议使用适当的
select_lated()
调用自己构建comment_list
QuerySet
。如果经常使用,请创建一个从其他视图调用的实用函数。如果您希望整个框架都以这种方式运行...您必须进行猴子修补。
这不是我会轻易做的事。还有其他方法可以解决这个特定问题,但您确实“一口气”问了。
将其放在
INSTALLED_APPS
models.py
文件中的某个位置。我实际上有一个monkey_patch
应用程序,用于修改django.contrib.auth.models.User.username
长度等(这是与这里不同的最后手段)。有关配置文件和 select_lated() 的问题
请注意,您的
UserProfile
类需要一个OneToOneField
到User
,其lated_name
等于您传递给select_lated()
的内容。在我的示例中,它是profile
并且您需要 django 1.2+。我记得以前偶然发现过这一点。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 queryOuch!
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 appropriateselect_related()
calls. If it's used often, create a utility function called from your other views.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 amonkey_patch
app for modifyingdjango.contrib.auth.models.User.username
lengths and such (which is a last resort unlike here).Gotchas with profiles and select_related()
Note that your
UserProfile
class needs aOneToOneField
toUser
with arelated_name
equal to what you pass toselect_related()
. In my example it'sprofile
and you need django 1.2+. I recall stumbling on that before.假设您有这样的设置:
您可以使用以下选择相关:
Comments.objects.select_lated('user__pk','user__profile__pk')
,这应该可以满足您的要求。您必须扩展评论框架。这相当简单。基本上,创建您自己的评论应用程序。您可以查看 django-threadedcomments 来获取灵感(实际上,在某些方面它是无论如何,已经是一个更好的实现了)。
您可以将以下代码插入到 django 线程注释应用程序中,以确保它始终使用 select 相关的(在 models.py 中):
并替换
为 按照
将线程注释集成到您的应用程序中的说明进行操作。
然后,在模板中,我认为您必须引用
.profile
而不是.get_profile
。可能是 Django 会自动考虑这一点,因此只要
.profile
可用,get_profile
就不会生成另一个数据库命中。Assuming that you have a setup like so:
You can use the following select related:
Comments.objects.select_related('user__pk','user__profile__pk')
and that should do what you want.You'll have to extend the comments framework. This is fairly straightforward. Basically, create your own comments app. You can look at django-threadedcomments for inspiration (and, actually, in some ways it's already a better implementation to use anyway).
Here's code you can insert into the django-threaded comments app to make sure it always uses the select related (in models.py):
and replace
with
Follow the instructions for integrating threadedcomments into your app.
Then, in the template, I think you'll have to reference
.profile
instead of.get_profile
.It may be that Django automatically factors this in, so
get_profile
will not generate another db hit so long as.profile
is available.在此示例中不能使用 select_lated(),因为 User 是配置文件的外键,反之亦然。
为了避免使用缓存(这可能是最好的选择),您可以使用配置文件模型的外键为评论创建代理模型。那么你可以写:
You can't use select_related() in this example, because User is foreign key of profile, not vice versa.
To avoid using cache (which is probably the best option) you could create proxy model for Comment with foreign key to your profile model. then you could write: