【问题标题】:Can I make a Django query that returns a list per item?我可以创建一个 Django 查询来返回每个项目的列表吗?
【发布时间】:2022-06-14 14:31:20
【问题描述】:

我有 3 个这样的模型:

class Person(models.Model):
    name = models.CharField(max_length=100)

class Place(models.Model):
    name = models.CharField(max_length=100)

# ManyToMany Through Table
class PersonPlace(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    place = models.ForeignKey(Place, on_delete=models.CASCADE)

PersonPlace 以多对多关系链接 Person 和 Place。

我想要一个数据库查询,它将为我提供每个人 id 的地点列表(每个人访问过的地点列表)。

是否可以通过 ORM 进行聚合,而无需 Python 将其放在一起?

预期回报类似于:{1: [4,5,6], 2: [1,2,5]}

这里的键是用户 ID,值是每个用户访问过的地点 ID。注意:结果不需要是字典,但我认为它会是类似字典的东西。

【问题讨论】:

标签: python django django-models django-queryset


【解决方案1】:

如果你使用的是postgres,你可以使用ArrayAgg..[Django-doc]:

from django.contrib.postgres.aggregates import ArrayAgg


for person in Person.objects.annotate(places=ArrayAgg("personplace__place")): 
    print(person.__dict__)

这给出了以下输出:

# ommitted unnecessary keys
{'id': 1, 'name': '1', 'places': ['2', '3']}
{'id': 2, 'name': '2', 'places': ['1', '2', '3']}

在后台,这一切都是通过以下查询在您的数据库上完成的:

SELECT 
    "person"."id", 
    "person"."name", 
    ARRAY_AGG("personplace"."place_id" ) AS "places" 
FROM 
    "person" 
LEFT OUTER JOIN 
    "personplace" 
ON 
    ("person"."id" = "personplace"."person_id") 
GROUP BY 
    "person"."id"

【讨论】:

  • 这看起来很完美!我实际上确实使用 PostgreSQL,所以这应该很好用!出于好奇 - 如果我们需要在其他数据库上执行此操作,是否需要手动编写某种长查询?
  • 暂时没有使用其他 rdbms,所以不太确定
【解决方案2】:

这将返回一个人的地点列表

person_object = Person.objects.get(name="admin")
place_objects_ids_query_set = PersonPlace.objects.filter(person=person_object).values_list('place', flat=True)
place_objects_ids_list = list(place_objects_ids_query_set)
print(place_objects_ids_list)

如果您需要很多人的地点列表

persons_objects = Person.objects.all()
place_objects_ids_query_set = PersonPlace.objects.filter(person__in=persons_objects).values_list('place', flat=True)
place_objects_ids_list = list(place_objects_ids_query_set)
print(place_objects_ids_list)

【讨论】:

  • 第一部分 - 一个人的地点列表 - 非常简单。第二部分也很简单。我要找的东西有点复杂。它基本上是一本人物词典,每个人都有他们去过的地方的列表。
  • 我想你可能会使用 django rest 框架来完成这个任务,它可能会返回 dict,它会被快速处理
  • 好像你想要 DRF 序列化器
  • 返回类型不是重点。它不需要是一个字典。我需要数据库查询来返回用户列表,以及每个用户访问过的地方。我确信我可以做单独的查询,然后用 Python 将它们拼接在一起,但这对于大型数据集来说效率很低。
猜你喜欢
  • 2015-12-14
  • 1970-01-01
  • 2021-12-17
  • 2011-01-28
  • 2012-12-23
  • 2021-01-19
  • 1970-01-01
  • 2014-04-07
  • 1970-01-01
相关资源
最近更新 更多