首页 > 解决方案 > Django ORM如何获取按字段分组的原始值

问题描述

我有一个像这样的模型:

class CPUReading(models.Model):
    host = models.CharField(max_length=256)
    reading = models.IntegerField()
    created = models.DateTimeField(auto_now_add=True)

我正在尝试获得如下所示的结果:

{
    "host 1": [
        {
            "created": DateTimeField(...),
            "value": 20
        },
        {
            "created": DateTimeField(...),
            "value": 40
        },
        ... 
    ],
    "host 2": [
        {
            "created": DateTimeField(...),
            "value": 19
        },
        {
            "created": DateTimeField(...),
            "value": 10
        },
        ... 
    ]
}

我需要它按主机分组并按created.

我已经尝试了很多东西,包括使用values()andannotate()来创建一个GROUP BY语句,但我认为我必须遗漏一些东西,因为为了使用GROUP BY它,我似乎需要使用一些我真的不想做的聚合函数。reading我需要按主机字段分组并按创建字段排序的字段的实际值。

这或多或少是任何图表库需要数据的方式。

我知道我可以使用 python 代码或原始 sql 查询来实现它,但我更喜欢使用 django ORM,除非它明确禁止这种查询。

标签: pythonpython-3.xdjangodjango-orm

解决方案


据我所知,ORM 中没有任何东西可以让这变得简单。如果您想在没有原始查询的情况下在 ORM 中执行此操作,并且如果您愿意并且能够更改数据结构,则可以主要在 ORM 中解决此问题,并将 Python 代码保持在最低限度:

class Host(models.Model):
    pass

class CPUReading(models.Model):
    host = models.ForeignKey(Host, related_name="readings", on_delete=models.CASCADE)
    reading = models.IntegerField()
    created = models.DateTimeField(auto_now_add=True)

有了这个,您可以使用两个具有相当干净代码的查询:

from collections import defaultdict

results = defaultdict(list)
hosts = Host.objects.prefetch_related("readings")
for host in hosts:
    for reading in host.readings.all():
        results[host.id].append(
            {"created": reading.created, "value": reading.reading}
        )

或者您可以使用一个查询和一个循环更有效地执行此操作:

from collections import defaultdict

results = defaultdict(list)
readings = CPUReading.objects.select_related("host")
for reading in readings:
    results[reading.host.id].append(
        {"created": reading.created, "value": reading.reading}
    )

推荐阅读