Сортировать по связанной модели с ForeignKey - PullRequest
3 голосов
/ 09 июля 2019

Мне нужно выполнить сортировку записей Credit по связанным моделям CreditPayment.

models.py

class Credit(models.Model):
    hot = models.BooleanField(default=False)


class CreditPayment(models.Model):
    credit = models.ForeignKey(Credit)
    period_to = models.PositiveIntegerField()
    rate = models.DecimalField(max_digits=7, decimal_places=2)

views.py

credits = credits.filter(hot=False).distinct().order_by(...)

Пример входных данных:

Credit #1:
CreditPayment #1:
period_to = 12
rate = 10

CreditPayment #2:      (minimal)
period_to = 10
rate = 8

CreditPayment #3:      
period_to = 9
rate = 10

Credit #2:
CreditPayment #1:        (minimal)
period_to = 6
rate = 20

CreditPayment #2:
period_to = 9
rate = 20

Credit #3:
CreditPayment #1:
period_to = 12
rate = 8

CreditPayment #2:
period_to = 9
rate = 11

CreditPayment #3:       (minimal)
period_to = 9
rate = 8

В результате выборка уменьшается до:

Credit #1:    
CreditPayment #2:
period_to = 10
rate = 8

Credit #2:
CreditPayment #1:
period_to = 6
rate = 20

Credit #3:
CreditPayment #3:
period_to = 9
rate = 8

Результат:

Кредит № 3 -> Кредит № 1 -> Кредит № 2

Как видите, сначала был выбран минимум CreditPayment для каждого Credit (credits при views.py ). Затем, согласно этим минимумам CreditPayment, все Credit сортируются. Если для двух записей одинаковая ставка, сравните эти записи по period to. Насколько я понимаю, здесь нужно как-то применить агрегацию .

1 Ответ

3 голосов
/ 09 июля 2019

Использование annotate() & prefetch_related()

models.py

class CreditPayment(models.Model):
    credit = models.ForeignKey(Credit, related_name='creditpayments')
    ....

views.py

from django.db.models import Max, Min, Prefetch

prefetch = Prefetch('creditpayments', CreditPayment.objects.all())
sorted_credits = Credit.objects.all().prefetch_related(prefetch).annotate(min_rate=Min('creditpayments__rate')).annotate(max_period_to=Max('creditpayments__period_to')).order_by('min_rate', '-max_period_to')
...