簡體   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