我有一个由用户上传的对象,它包含几个细节,但为了清楚起见,可以简单地通过以下模型表示来定义 -
在此之后,其他用户可以对该用户上传的内容进行upvote和downvote,从而投票模型。
现在我想获得要在模板中显示的所有对象的upvotes和downvotes。因此,我向ObjectDetail
类添加了两个函数,作为upvote和downvote。
这个模型的问题是,比如有20个对象,对于每个对象,2个查询被激活一个获得upvote而另一个获得downvote。因此,没有。对于20个对象,查询现在是40。
调整这个以减少查询数量并在每个对象上显示upvotes和downvotes的好方法是什么?
class ObjectDetail(models.Model):
title = models.CharField()
img = models.ImageField()
description = models.TextField()
uploaded_by = models.ForeignKey(User, related_name='voted_by')
@property
def upvote(self):
upvote = Vote.objects.filter(shared_object__id = self.id,
vote_type = True).count()
return upvote
@property
def downvote(self):
downvote = Vote.objects.filter(shared_object__id = self.id,
vote_type = False).count()
return downvote
class Vote(models.Model):
vote_type = models.BooleanField(default = False)
voted_by = models.ForeignKey(User, related_name='voted_by')
voted_for = models.ForeignKey(User, related_name='voted_for')
shared_object = models.ForeignKey(ObjectDetail, null=True, blank=True)
dtobject = models.DateTimeField(auto_now_add=True)
答案 0 :(得分:0)
在https://docs.djangoproject.com/en/1.5/ref/models/querysets/#django.db.models.query.QuerySet.extra的文档中 我在这里使用extra()子句注入一些原始的sql。
编辑:这适用于名为“投票”且至少是Sqlite的应用。根据需要更改vot_*
表名称。
from django.db.models import Count
objects = ObjectDetail.objects.all().extra(
select={ 'upvotes': '''SELECT COUNT(*) FROM vot_vote
WHERE vot_vote.shared_object_id = vot_objectdetail.id
AND vot_vote.vote_type = 1''',
'downvotes': '''SELECT COUNT(*) FROM vot_vote
WHERE vot_vote.shared_object_id=vot_objectdetail.id
AND vot_vote.vote_type = 0'''})
现在objects
中的每个元素都有一个upvotes和downvotes属性。
答案 1 :(得分:0)
一方面,django确实为您提供了在必要时编写原始SQL的功能。但是这个例子很简单,你不必使用原始SQL来获取这些信息。
Django将推迟查询,直到您访问查询集的结果。因此,您可以尝试使用查询集和Q对象组合整个查询,然后访问组合查询的结果 - 这应该为所有结果触发一个数据库查询(或每个模型一个,而不是每个实例一个)。
那么,该怎么做?您希望获取给定的ObjectDetail记录集的所有投票记录。我假设你有一个ObjectDetail记录的id列表。
不幸的是,您的upvote和downvote属性会在其查询集上返回“count”的结果。这被视为“过滤器”调用产生的查询集的“访问结果”。我会更改这些方法定义以引用向后关系对象管理器vote_set,如下所示:
@property
def upvote(self):
answer = 0
for vote in self.vote_set.all ():
if vote.vote_type:
answer += 1
return answer
@property
def downvote(self):
answer = 0
for vote in self.vote_set.all ():
if not vote.vote_type:
answer += 1
return answer
注意我们只访问当前对象的查询集。在这个阶段,我们假设orm可以访问缓存的结果。
现在,在视图和/或模板中,我们想要组装大型复杂查询。
我的例子是功能性视图:
def home (request):
# just assigning a constant list for simplicity.
# Also was lazy and did 10 examples rather than 20.
objids = [ 1, 5, 15, 23, 48, 52, 55, 58, 59, 60 ]
# make a bunch of Q objects, one for each object id:
q_objs = []
for objid in objids:
q_objs.append(Q(id__exact = objid))
# 'or' them together into one big Q object.
# There's probably a much nicer way to do this.
big_q = q_objs[0]
for q_obj in q_objs[1:]:
big_q |= q_obj
# Make another queryset that will ask for the Vote objects
# along with the ObjectDetail objects.
# Try commenting out this line and uncommenting the one below.
the_objects = ObjectDetail.objects.filter(big_q).prefetch_related('vote_set')
# the_objects = ObjectDetail.objects.filter(big_q)
template = 'home.html'
context = {
'the_objects' : the_objects,
}
context_instance = RequestContext (request)
return render_to_response (template, context, context_instance)
以下是相关文档的一些指示:
https://docs.djangoproject.com/en/1.5/topics/db/queries/#querysets-are-lazy https://docs.djangoproject.com/en/1.5/ref/models/querysets/#when-querysets-are-evaluated https://docs.djangoproject.com/en/1.5/topics/db/queries/#complex-lookups-with-q-objects https://docs.djangoproject.com/en/1.5/topics/db/queries/#following-relationships-backward