筛选查询集以仅返回每个用户的最佳结果

时间:2015-12-14 01:20:56

标签: python django django-models django-queryset

我有几个django模型,其中一个模型包含不同事件的大量用户结果。我正在寻找一种方法来生成一个查询集,该查询集仅包含每个用户的最佳(最高)结果,该结果还附加了其他属性(如结果的日期)。

我的模型与使用内置用户模型一样显示:

class CombineEvents(models.Model):
    team = models.ForeignKey(Team)
    event = models.CharField(max_length=100)
    metric = models.CharField(max_length=100)
    lead_order = models.IntegerField()

    def __unicode__(self):
        return self.event

class CombineResults(models.Model):
    user = models.ForeignKey(User)
    date = models.DateField()
    event = models.ForeignKey(CombineEvents)
    result = models.FloatField()

    def __unicode__(self):
        return str(self.date) + " " + str(self.event)

我正在迭代每个事件并附加事件结果的查询集,这工作正常,但我希望该子查询集只为每个用户包含一个对象,该对象应该是该用户的最佳选择结果。我的查询集代码如下:

    combine_events = CombineEvents.objects.filter(team__id=team_id)
    for event in combine_events:
        event.results = CombineResults.objects.filter(event=event)

我不确定如何过滤到每个用户的最佳结果。我想使用这些查询集来创建排行榜,所以我仍然希望能够获得最佳结果的日期和用户名,但不希望排行榜允许多个点每个用户。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

由于您的CombineResults模型与CombineEvents的FK关系,您可以执行以下操作:

combine_events = CombineEvents.objects.filter(team__id=team_id)
for event in combine_events:
    result = event.combineresults_set.order_by('-result')[0]

combineresults_set属性由FK字段自动生成,但您可以通过指定related_name关键字参数将其设置为更有用的内容:

class CombineResults(models.Model):
    event = models.ForeignKey(CombineEvents, related_name='results')

可让您拨打event.results.order_by(...)。这里的文档中有更多内容: https://docs.djangoproject.com/en/1.9/topics/db/queries/#following-relationships-backward

请注意,这不是最适合数据库的方法,因为您将有效地访问数据库一次以获得combine_events(一旦开始迭代),然后再次< em>该列表中的每个事件。使用prefetch_related()可能更好,您可以使用prefetch_related()进行两个数据库查询。文档可以是found here

queryset.all()但是默认会为相关文档执行Prefetch,您可以使用from django.db.models import Q, Max combine_events = CombineEvents.objects \ .filter(team_id=team_id) \ .prefetch_related('combineresults_set') for event in combine_events: # Get the value of the best result per user result = event.combineresults_set.values('user').annotate(best=Max('result')) # Now construct a Q() object, note this will evaluate the result query base_q = Q() for res in result: # this is the equivalent to base_q = base_q | .... base_q |= (Q(user_id=res['user']) & Q(result=res['best'])) # Now you're ready to filter results result = event.combineresults_set.filter(base_q) 对象documented here进一步控制这些文档。

修改 抱歉让问题出错。每个事件获得每个用户的最佳结果(这是我认为你想要的)并不是那么简单。我可能会做这样的事情:

<%= f.text_area :body %>

您可以阅读有关Q对象here的更多信息,或者使用RawSQL等编写自己的SQL。或者等待有更好主意的人......