vikkyshostak
@vikkyshostak
< This head full of dreams.

Django. Как сделать агрегацию каждого элемента в QuerySet по минимальному значению из его ForeignKey поля?

Доброго времени суток.

Подскажите, пожалуйста, как сделать агрегацию каждого элемента в QuerySet по минимальному значению из его связанного ForeignKey поля? Поясню на примере своего кода, чего мне вообще надо получить в результате.

Итак, есть модель Tours:

# /tours/models.py

class Tours(models.Model):
    country = models.CharField(...)
    ...


class ToursHotels(models.Model):
    tour = models.ForeignKey(Tours, on_delete=models.CASCADE, default=None)
    cost = models.IntegerField(...)
    ...

К этой модели в админке прицепляется ToursHotels (из той же модели, см. выше) через inlines = [...]:

# /tours/admin.py

class TourHotelsInlineAdmin(admin.TabularInline):
    """
    Inline element for `TourHotels` model
    Use table view (admin.TabularInline) on `ToursAdmin`
    """
    model = ToursHotels
    extra = 1  # number of viewed columns (default: 3)

    def get_extra(self, request, obj=None, **kwargs):
        """
        Dynamically sets the number of extra forms
        Return 0: related object already exists or the extra configuration otherwise
        """
        if obj:
            return 0
        return self.extra


@admin.register(Tours)
class ToursAdmin(admin.ModelAdmin):
    inlines = [
        TourHotelsInlineAdmin,
    ]

В результате, при создании нового материала <code>Tours</code>, всё выглядит вот так: (как и ожидалось)
Screen-Shot-2017-11-11-at-14-47-33.png


Далее, определяю вьюшку для вывода:

# /tours/views.py

class ToursIndex(View):
    """ Tours Index View """

    template_name = 'tours/tours_index.html'

    def get(self, request):
        tours = Tours.objects.filter(date__gte=datetime.now())
        hotels = Tours.objects.aggregate(Min('tourshotels__cost'))

        return render(request, self.template_name, {'tours': tours, 'hotels': hotels})

И, наконец, шаблон:

<!-- /templates/tours/tours_index.html -->

{% for tour in tours %}
    <div class="columns">
      <div class="column">
        {{ tour.country }}
      </div>
      <div class="column">
        от {{ hotels.cost__min | intcomma }} руб.
      </div>
    </div>
{% endfor %}

Создаю тестовые материалы (Tours) и ожидаю увидеть в выводе следующее:

Кипр       от 27 500 руб.
Турция     от 35 000 руб.
Греция     от 43 500 руб.
...

Но вместо этого, получаю общую минимальную стоимость у каждого материала, то есть:

Кипр       от 27 500 руб.
Турция     от 27 500 руб.
Греция     от 27 500 руб.
...

Отсюда и вопрос. Как сделать агрегацию, как в первом варианте?

Буду рад толковым комментариям.
Заранее благодарю!
  • Вопрос задан
  • 431 просмотр
Решения вопроса 1
vikkyshostak
@vikkyshostak Автор вопроса
< This head full of dreams.
Спасибо javedimka за наводку.

Решение: использовать annotate(), как и описано в документации.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы