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