You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效将Django QuerySet结果转换为指定结构的字典

问题

现有Django模型:

class User(models.Model):
    customer_id = models.TextField()
    date_time_period_start = models.DateField()
    date_time_period_end = models.DateField()
    total_sales = models.IntegerField()

对应数据库表数据:

customer_id | date_time_period_start | date_time_period_end | total_sales
1           | 2023-04-01             | 2023-04-01           | 10
1           | 2023-04-02             | 2023-04-02           | 20
1           | 2023-04-03             | 2023-04-03           | 30

需求是通过Django查询返回一个Python字典,以date_time_period_start的值为键,对应值为包含各字段键值对的字典,示例结构如下:

{
    '2023-04-01': {'date_time_period_start': '2023-04-01', 'date_time_period_end': '2023-04-01', 'customer_id': 1, 'total_sales': 10},
    '2023-04-02': {'date_time_period_start': '2023-04-02', 'date_time_period_end': '2023-04-02', 'customer_id': 1, 'total_sales': 20},
    '2023-04-03': {'date_time_period_start': '2023-04-03', 'date_time_period_end': '2023-04-03', 'customer_id': 1, 'total_sales': 30},
}

目前已通过循环列表实现需求,代码如下:

records = list(
    self.model.objects
    .values(
        "customer_id",
        "date_time_period_start",
        "date_time_period_end",
        "total_sales",
    )
)

records_dict = {}
for record in records:
    records_dict[record["date_time_period_start"]] = {
        "date_time_period_start": record["date_time_period_start"],
        "date_time_period_end": record["date_time_period_end"],
        "customer_id": record["customer_id"],
        "total_sales": record["total_sales"],
    }

尝试过使用values()和annotate()方法,但得到的是QuerySet列表,并非目标字典结构:

from django.db.models import F

result = self.model.objects.values('date_time_period_start').annotate(date_time_period_end=F('date_time_period_end'),
    total_sales=F('total_sales'),
    customer_id=F('customer_id'),
)

询问是否存在无需循环列表的更高效实现方式。


解决方案

1. 字典推导式(简洁高效)

用Python字典推导式替代显式循环,代码更紧凑,执行效率与循环接近但可读性更强:

records = self.model.objects.values(
    "customer_id",
    "date_time_period_start",
    "date_time_period_end",
    "total_sales",
)

records_dict = {
    str(record["date_time_period_start"]): record
    for record in records
}

注意:由于date_time_period_start是DateField类型,需要转换为字符串作为字典键,与示例结构保持一致。

2. 生成器表达式转字典(内存友好)

如果数据量极大,不想一次性加载所有数据到列表,可使用生成器表达式配合dict()转换,减少内存占用:

records = self.model.objects.values(
    "customer_id",
    "date_time_period_start",
    "date_time_period_end",
    "total_sales",
)

records_dict = dict(
    (str(record["date_time_period_start"]), record)
    for record in records
)

补充说明

  • Django ORM本身没有直接返回该结构的API,数据库查询返回的是集合数据,需在Python层面转换为目标字典结构。
  • 上述两种方式本质仍是遍历QuerySet,但QuerySet是惰性求值的,仅在遍历时执行数据库查询,内存效率更高。
  • 需确保date_time_period_start的值唯一,否则后续记录会覆盖之前的(与原循环逻辑一致)。

内容的提问来源于stack exchange,提问作者Vincent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 03:48:16