我有几个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)
我不确定如何过滤到每个用户的最佳结果。我想使用这些查询集来创建排行榜,所以我仍然希望能够获得最佳结果的日期和用户名,但不希望排行榜允许多个点每个用户。有什么想法吗?
答案 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。或者等待有更好主意的人......