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

在Django的.values()方法中获取Seller模型对象的方法

问题描述

我有如下销售数据:

卖家名称销售日期
Alice2023/05/01
Bob2023/05/03
Alice2023/05/15
Alice2023/05/31
Carl2023/05/01
Carl2023/05/04
Bob2023/05/20
Carl2023/05/21

我用下面的Django查询集获取每个卖家的首次和末次销售日期:

sales = (Sale.objects.filter(created_at__year=2023, created_at__month=5)
            .values('seller')
            .annotate(min_date=Min('created_at'), max_date=Max('created_at'))
            .order_by()
)

查询能正常运行,但返回结果里的seller字段是ID,不是Seller模型对象:

{'seller': 1, 'min_date': datetime.datetime(2023, 5, 1, 3, 52, 12, tzinfo=<UTC>), 'max_date': datetime.datetime(2023, 5, 31, 7, 32, 1, tzinfo=<UTC>)}
{'seller': 2, 'min_date': datetime.datetime(2023, 5, 3, 4, 34, 11, tzinfo=<UTC>), 'max_date': datetime.datetime(2023, 5, 20, 5, 52, 1, tzinfo=<UTC>)}
{'seller': 3, 'min_date': datetime.datetime(2023, 5, 1, 11, 50, 5, tzinfo=<UTC>), 'max_date': datetime.datetime(2023, 5, 21, 10, 21, 1, tzinfo=<UTC>)}

怎么修改查询集才能获取到Seller模型对象?

更新:我的models.py相关代码如下:

class Seller(models.Model):
    name = models.CharField(max_length=100, blank=True, default='')

class Sale(models.Model):
    seller = models.ForeignKey(Seller, on_delete=models.CASCADE, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

解决方案

方法1:从Seller模型反向查询(推荐)

直接从Seller模型出发,关联Sale表并做聚合统计,返回的就是完整的Seller对象,同时带上聚合的日期字段:

from django.db.models import Min, Max

sellers_with_dates = Seller.objects.filter(
    sale__created_at__year=2023, sale__created_at__month=5
).annotate(
    min_date=Min('sale__created_at'),
    max_date=Max('sale__created_at')
).distinct()

使用时直接访问对象属性即可:

for seller in sellers_with_dates:
    print(seller.name)
    print(seller.min_date)
    print(seller.max_date)

这种方式只需要一次数据库查询,效率最高,代码也最简洁。

方法2:保留Sale查询并获取卖家完整信息

如果坚持从Sale模型发起查询,可以在values中指定卖家的具体字段,结合select_related预加载关联数据,返回包含卖家信息的字典:

sales = (Sale.objects.filter(created_at__year=2023, created_at__month=5)
            .select_related('seller')
            .values('seller__id', 'seller__name')
            .annotate(min_date=Min('created_at'), max_date=Max('created_at'))
            .order_by()
)

返回结果示例:

{'seller__id': 1, 'seller__name': 'Alice', 'min_date': ..., 'max_date': ...}

你可以直接使用字典中的卖家信息,或者手动组装成Seller对象。

方法3:遍历结果时补全卖家对象(不推荐)

如果不想修改原查询结构,可以在遍历结果时根据ID查询卖家,但这种方式会触发N+1次数据库查询,仅适合数据量极小的场景:

for item in sales:
    item['seller_obj'] = Seller.objects.get(id=item['seller'])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 09:14:56