【问题标题】:Django aggregation Many To Many into list of dictDjango将多对多聚合到dict列表中
【发布时间】:2022-07-19 04:43:20
【问题描述】:

我尝试执行此操作已经有几个小时了,但我无法弄清楚。

假设我有一个 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()

所以它只是一个具有多个地址的简单 Person。 然后我创建了一些对象:

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
            }
        ]
    }
]

我能得到的最好的结果是对 Django 使用 ArrayAgg 和 JSONBagg 运算符(顺便说一下,我正在使用 POSTGRESQL):

from django.contrib.postgres.aggregates import JSONBAgg, ArrayAgg
result = Person.objects.values(
   'name',
   addresses=JSONBAgg('city')
)

但这还不够,我不能像我想做的那样直接从查询中提取一些字典,只是一个值列表或无用的使用:

addresses=JSONBAgg(('city','zip'))

它返回一个带有随机键和我作为输入作为值传递的字符串的字典。

谁能帮帮我?

谢谢

【问题讨论】:

标签: python django django-queryset aggregation


【解决方案1】:

person.address 已经拥有一个地址查询集。从那里你可以使用 list-comprehension / model_from_dict 来获取你想要的值。

【讨论】:

    【解决方案2】:

    您的要求:在 Django 中的 group_by (values) 之后对自定义 JSON 对象进行聚合。

    目前,据我所知,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)", ())))
    

    希望对你有帮助。

    【讨论】:

      【解决方案3】:

      如果你使用 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))
      

      【讨论】:

        猜你喜欢
        • 2020-11-04
        • 2021-03-04
        • 2020-08-29
        • 1970-01-01
        • 1970-01-01
        • 2022-09-23
        • 2015-11-01
        • 1970-01-01
        • 2011-04-06
        相关资源
        最近更新 更多