0

我有一个由用户上传的对象,它包含几个细节,但为了清楚起见,可以通过以下模型表示简单地定义 -

在此之后,其他用户可以对该用户上传的内容进行投票和否决,从而形成投票模型

现在我想获得要在模板中显示的所有对象的赞成票和反对票。因此,我在类中添加了两个函数ObjectDetail,分别是 upvote 和 downvote。

这个模型的问题是,假设有 20 个对象,每个对象触发 2 个查询,一个获得赞成票,另一个获得反对票。因此没有。20 个对象的查询现在是 40 个。

什么是调整它以减少查询数量并在每个对象上显示赞成票和反对票的好方法?

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)
4

2 回答 2

0

它在https://docs.djangoproject.com/en/1.5/ref/models/querysets/#django.db.models.query.QuerySet.extra的文档中 我正在使用 extra() 子句注入一些原始 sql这里。

编辑:这适用于一个名为“vot”的应用程序,至少是 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 属性。

于 2013-05-08T06:36:22.947 回答
0

一方面,django 确实为您提供了在必要时编写原始 SQL 的能力。但是这个例子很简单,你不应该使用原始 SQL 来获取这些信息。

Django 将推迟查询,直到您访问查询集的结果。因此,您可以尝试使用查询集和 Q 对象组合整个查询,然后访问组合查询的结果 - 这应该会触发所有结果的一个数据库查询(或每个模型一个,而不是每个实例一个)。

那么,该怎么做呢?您想要获取给定 ObjectDetail 记录集的所有 Vote 记录。我假设你有一个 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 - 评估 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

于 2013-07-08T22:41:04.763 回答