[英]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.