2017-01-24 19 views
0

獲取最新的成本值的列表,我有以下的Django模型:Django的:通過

class Costs(models.Model): 
    """Represents a cost for a vendor/locale combo.""" 
    valid_from_date = models.DateField() 
    vendor_id = models.ForeignKey('Vendor') 
    locale_id = models.ForeignKey('Locale') 
    cost = models.FloatField() 

爲了保存歷史數據,當成本變化的供應商/區域組合,我們只是增加一個新的用新的valid_from_date進入表格(而不是覆蓋舊錶格)。

Costs.objects.all()從表格中獲取所有數據是相當容易的。通過Costs.objects.filter(vendor_id=1, locale_id=10).latest()獲得單個供應商/區域設置的當前值也很容易。

我感興趣的是每個供應商/地區組合的最新成本值。所以,基本上在每個組合上運行latest()函數,並得到一個列表/查詢集。

例如,給定下列一組數據:

  • 編號:100,日期:2017年1月1日,供應商:1,區域設置:10,造價:$ 1
  • 編號:200,日期:2017-2-1,供應商:1,區域設置:10,成本:$ 2
  • 編號:300,日期:2017-1-1,供應商:2,區域設置:10,成本:3美元
  • Id: 400,Date:2017-2-1,Vendor:2,Locale:10,Cost:$ 5
  • Id:500,Date:2017-1-1,Vendor:2,Locale:20,Cost:$ 5

我希望下面的數據傳回:

  • 編號:200,日期:2017年2月1日,供應商:1,地點:10,費用:$ 2
  • 編號:400,日期:2017年2月1日,銷售商:2,區域設置:如圖10所示,費用:$ 4
  • 編號:500,日期:2017年1月1日,銷售商:2,區域設置:20,費用:$ 5

我已經多次閱讀了aggregation docs,但似乎無法找到任何匹配的內容完美。

我正在使用Django 1.10和MySQL後端。

任何想法?謝謝。

回答

0

我最終直接在Python中完成它。我把所有東西都分成了一個列表字典(關鍵是Vendor/Locale組合),然後從每個列表中取出最大值。本質上,這:

groups = collections.defaultdict(list) 
for cost in Cost.objects.all(): 
    groups['{} {}'.format(cost.vendor_id, cost.locale_id].append(cost) 
return [max(value, key=operator.attrgetter('date')) 
     for value in groups.itervalues()] 
1

如果你有postgres作爲後端,你可以使用一些distinct('vendor_id', 'locale_id')並且很高興。如果你不這樣做,你必須更具創造性:

from django.db.models import Max 

ids = Costs.objects.\ 
    values('vendor_id', 'locale_id').\ # grouping based on values will be used for annotation 
    annotate(mx=Max('id')).\  # annotate the max id for each group 
    order_by().\     # clear any default ordering to avoid a total mess 
    values_list('mx', flat=True) # retrieve all the max ids 

costs = Costs.objects.filter(id__in=ids) 

這個shuold結果在一個單一的數據庫查詢。所有這些都可以從docs on the interaction of values, order_by, and annotate艱難提取;-)

+0

感謝您的答案。這似乎是正確的方向,但我不認爲它是那裏。隨着日期的增加(歷史數據已被重新加載),id值不能保證更大。所以只是因爲A.date> B.date並不意味着A.id> B.id.如果我們使用'Max('date')'而不是'id'註釋,我們就不能執行'Costs.objects.filter()'行。有任何想法嗎? – Chad