Django ORM запрос

Нужна помощь составить запрос, у меня есть модель:

class Member(models.Model):
    customer = models.CharField(max_length=50)
    item = ArrayField(models.CharField(max_length=50))
    total = models.IntegerField()

Нужно сделать запрос для вывода только первых пяти customer по полю total (это я знаю, как сделать), но далее в поле item каждого customer нужно вывести только те камни, которые встречаются не менее двух раз у других customer этого топ пять.

Как правильно реализовать этот запрос?


Ответы (1 шт):

Автор решения: Jack_oS

Можно выбрать топ-5 members по total:

members_qry = Member.objects.order_by('-total')[:5]

и записать в словарь:

members = [{'customer': m.customer, 'stones': m.item, 'total': m.total} for m in members_qry]

Допустим, members выглядит так:

>>> members
[
    {'customer': 'joe', 'total': 13, 'stones': ['бриллиант', 'сапфир', 'аметист']},
    {'customer': 'dou', 'total': 12, 'stones': ['изумруд', 'сапфир', 'малахит']},
    {'customer': 'foo', 'total': 12, 'stones': ['топаз', 'берилл', 'оникс', 'аметист', 'изумруд']},
    {'customer': 'bar', 'total': 9, 'stones': ['изумруд', 'сапфир', 'малахит']},
    {'customer': 'spam', 'total': 9, 'stones': ['топаз', 'аметист', 'сапфир', 'берилл']}
]

Тогда количество камней у всех будет:

stones_dict = dict()

for m in members:
    for s in m['stones']:
        stones_dict[s] = stones_dict.get(s, 0) + 1

в stones_dict:

>>> stones_dict
{'бриллиант': 1, 'сапфир': 4, 'аметист': 3, 'изумруд': 3, 'малахит': 2, 'топаз': 2, 'берилл': 2, 'оникс': 1}

И потом удалить те камни, которые встречаются у двух и меньше members:

for m in members:
    for s in m['stones'].copy():
        if stones_dict[s] < 3:
            m['stones'].remove(s)

В итоге в members:

>>> members
[
    {'customer': 'joe', 'total': 13, 'stones': ['сапфир', 'аметист']}, 
    {'customer': 'dou', 'total': 12, 'stones': ['изумруд', 'сапфир']}, 
    {'customer': 'foo', 'total': 12, 'stones': ['аметист', 'изумруд']}, 
    {'customer': 'bar', 'total': 9, 'stones': ['изумруд', 'сапфир']}, 
    {'customer': 'spam', 'total': 9, 'stones': ['аметист', 'сапфир']}
]
→ Ссылка