Django агрегация Many To Many в список dict
Уже несколько часов я пытаюсь выполнить эту операцию, но так и не смог разобраться.
Допустим, у меня есть проект Django с двумя классами, такими как:
from django.db import models
class Person(models.Model):
name=models.CharField()
address=models.ManyToManyField(to=Address)
class Address(models.Model):
city=models.CharField()
zip=models.IntegerField()
Итак, это простое лицо, имеющее несколько адресов. Затем я создаю несколько объектов:
addr1=Address.objects.create(city='first', zip=12345)
addr2=Address.objects.create(city='second', zip=34555)
addr3=Address.objects.create(city='third', zip=5435)
person1=Person.objects.create(name='person_one')
person1.address.set([addr1,addr2])
person2=Person.objects.create(name='person_two')
person2.address.set([addr1,addr2,addr3])
Теперь начинается самая сложная часть, я хочу сделать один запрос, который вернет что-то вроде этого:
result = [
{
'name': 'person_one',
'addresses': [
{
'city':'first',
'zip': 12345
},
{
'city': 'second',
'zip': 34555
}
]
},
{
'name': 'person_two',
'addresses': [
{
'city':'first',
'zip': 12345
},
{
'city': 'second',
'zip': 34555
},
{
'city': 'third',
'zip': 5435
}
]
}
]
Лучшее, чего я смог добиться, это использование операторов ArrayAgg и JSONBAgg для Django (я на POSTGRESQL BY THE WAY):
from django.contrib.postgres.aggregates import JSONBAgg, ArrayAgg
result = Person.objects.values(
'name',
addresses=JSONBAgg('city')
)
Но этого недостаточно, я не могу вытащить лит словарей из запроса напрямую, как я хотел бы сделать, только список значений или что-то бесполезное, используя:
addresses=JSONBAgg(('city','zip'))
который возвращает словарь со случайными ключами и строками, которые я передал в качестве входных данных в качестве значений.
Может кто-нибудь мне помочь?
Спасибо
По-моему, вы уже задавали тот же вопрос здесь , но не ответили на комментарии.
Нашли ли вы решение проблемы? Со своей стороны, мне пришлось создать отдельный набор запросов, чтобы получить результаты, но я думаю, что это не является удовлетворительным решением.
person.address уже содержит набор адресов. Отсюда вы можете использовать list-comprehension / model_from_dict для получения нужных вам значений.
Ваше требование: Сделать агрегацию настроенных JSON объектов после group_by (значения) в Django.
В настоящее время, насколько мне известно, Django не предоставляет никакой функции для агрегации созданных вручную JSON объектов. Есть несколько способов решить эту проблему. Во-первых, сделать настраиваемую функцию, что довольно трудоемко. Однако есть и другой подход, который довольно прост: использовать обе агрегатные функции (ArrayAgg или JSONBAgg) и RawSQL вместе.
from django.contrib.postgres.aggregates import JSONBAgg, ArrayAgg
result = Person.objects.values('name').annotate(addresses=JSONBAgg(RawSQL("json_build_object('city', city, 'zip', zip)", ())))
Надеюсь, это поможет вам.
Если вы используете postgres, вы можете сделать следующее:
subquery = Address.objects.filter(person_id=OuterRef("pk")).annotate(
data=JSONObject(city=F("city"), zip=F("zip"))
).values_list("data")
persons = Persons.objects.annotate(addresses=ArraySubquery(subquery))