Как сделать группировку по в djano ORM

У меня есть модель заказа, как показано ниже:

class Order(models.Model):
    bill = models.ForeignKey(Bill, on_delete=models.PROTECT, null=True, blank=True)
    address_from = models.ForeignKey(Address, on_delete=models.PROTECT)
    address_to = models.ForeignKey(Address, on_delete=models.PROTECT)

Как я могу сгруппировать набор запросов и выполнить итерацию в каждой группе следующим образом:

bill = models.Bill.objects.create()
groups = Order.objects.all().group_by('address_from', 'address_to')

for group in groups:
    group.update(bill = bill)

Цель состоит в том, чтобы установить счет для каждой группы заказов, имеющих одинаковые адреса from и to.

Чтобы сделать то, что вы ищете, не существует group_by как такового, вместо этого я бы составил список со всеми уникальными комбинациями ваших 2 адресных полей, Для каждой группы отфильтруйте соответствующие команды и используйте update() для назначения указанного экземпляра Bill

Дополнительную информацию можно найти в документации, в частности, в разделах о values() и distinct() https://docs.djangoproject.com/en/5.1/ref/models/querysets/

Надеюсь, мой ответ поможет решить вашу проблему

Я решил эту проблему, объединив адрес из & адрес к первичным ключам в аннотированный уникальный ключ - uk - поле и отфильтровав каждый uk.

from django.db.models import CharField, Value
from django.db.models.functions import Concat

orders = models.Order.objects.annotate(
    addresses_uk=Concat('address_from__pk', Value('-'), 'address_to__pk',
        output_field=CharField())
    )

for uk in set(orders.values_list('addresses_uk', flat=True)):
    bill = models.Bill.objects.create(
        address_from=models.Address.objects.get(pk=int(uk.split("-")[0])),
        address_to=models.Address.objects.get(pk=int(uk.split("-")[1]))
    )
    orders.filter(addresses_uk=uk).update(bill=bill)

@Ahmed Ashraf ответил на вопрос. Тем не менее мы можем получать и создавать данные в bulk, что повысит производительность намного, с помощью:

orders = {
    (order.address_from, order.adress_to): order
    for order in models.Order.objects.filter(bill=None)
}

bills = []
for (item1, item2), order in orders.items():
    bill = models.Bill(address_from_id=item1, address_to_id=item2)
    bills.append(bill)
    order.bill = bill

Bill.objects.bulk_create(bills)
Order.objects.bulk_update(orders.values(), fields=('bill',))

Это будет работать с тремя запросами: один для получения всех заказов без bill, другой для создания всех bills, и, наконец, третий для обновления всех Order с созданными <<<6>>

>
Вернуться на верх