繁体   English   中英

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

[英]Filter queryset to return only the best result for each user

我有几个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)

我不确定如何过滤每个用户的最佳结果。 我想使用这些查询集来创建排行榜,因此我仍然希望能够获得最佳结果的日期和用户名,但是不希望排行榜为每个用户提供一个以上的位置。 有任何想法吗?

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

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

尽管可以通过指定related_name关键字参数将其设置为更有用的方法,但是FK字段会自动生成combineresults_set属性:

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 (一旦您开始迭代),然后再次访问该列表中的每个事件。 最好使用prefetch_related() ,您可以仅使用它进行两个数据库查询。 文档可以在这里找到

但是prefetch_related()将默认对相关文档执行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)

您可以在此处阅读有关Q对象的更多信息,或者使用RawSQL等类似方法编写自己的SQL。 或者等待有更好主意的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM