2017-01-24 8 views
0

У меня есть следующий 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().

Что мне нужно получить, это все последние значения стоимости для каждого компилятора vendor/locale. Таким образом, по существу выполняется функция latest() по каждой комбинации и в результате получается список/запрос.

Например, если следующий набор данных:

  • Id: 100, Дата: 2017-1-1, Производитель: 1, Язык: 10, стоимость: $ 1
  • Id: 200, Дата: 2017-2-1, Продавец: 1, Местность: 10, Стоимость: 2
  • Id: 300, Дата: 2017-1-1, Продавец: 2, Местность: 10, Стоимость: $ 3
  • Id: 400, Дата: 2017-2-1, Продавец: 2, Местность: 10, Стоимость: $ 4
  • Id: 500, Дата: 2017-1-1, Продавец: 2, Местность: 20, Стоимость: $ 5

Я хотел бы следующие данные обратно:

  • Id: 200, Дата: 2017-2-1, Производитель: 1, Locale: 10, стоимость: $ 2
  • Id: 400, Дата : 2017-2-1, Производитель: 2, Язык: 10, стоимость: $ 4
  • Id: 500, Дата: 2017-1-1, Производитель: 2, Язык: 20, стоимость: $ 5

Я читал через aggregation docs несколько раз, но не могу найти ничего, что соответствует в совершенстве.

Я использую Django 1.10 с бэкэнд MySQL.

Любые идеи? Спасибо.

ответ

0

Я закончил работу прямо в Python. Я сгруппировал все в словарь списков (с ключом, являющимся компилятором Vendor/Locale), а затем просто взял max из каждого списка. По существу, это:

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 в одном запросе db. Все это может быть трудно извлечено из 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

 Смежные вопросы

  • Нет связанных вопросов^_^