Как сделать группировку по в 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>>