You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Django中查询全部客户并关联指定日期范围的客户工单?

嘿,这个需求我做项目时也碰到过,用Django的查询API就能轻松搞定,给你两种实用的实现方案:

方案一:用Case/When条件标注工单字段

这种方法直接通过annotate给每个客户对象动态添加ticket字段,符合日期条件就返回工单,否则设为null

from django.db.models import Case, When, Value, OuterRef, Subquery
from django.utils import timezone

# 先定义你的日期范围(记得处理时区,避免时间偏差)
start_date = timezone.datetime(2024, 1, 1, tzinfo=timezone.utc)
end_date = timezone.datetime(2024, 6, 30, tzinfo=timezone.utc)

# 查询所有客户,并附加符合条件的工单
customers = Customer.objects.annotate(
    ticket=Case(
        When(
            # 判断关联工单的日期是否在范围内
            customerticket__date__range=(start_date, end_date),
            # 用Subquery取出当前客户对应的工单
            then=Subquery(CustomerTicket.objects.filter(customer=OuterRef('pk')).values('pk')[:1])
        ),
        # 不符合条件时返回null
        default=Value(None),
        # 指定输出字段类型,确保返回的是工单对象或null
        output_field=models.ForeignKey(CustomerTicket, on_delete=models.SET_NULL, null=True)
    )
).all()

# 使用示例:遍历客户获取工单
for customer in customers:
    print(f"客户:{customer.name},工单:{customer.ticket}")
方案二:用Prefetch预加载过滤后的工单

如果要优化查询性能(减少数据库请求次数),可以用Prefetch来预加载符合条件的工单,之后再处理成单个字段:

from django.db.models import Prefetch
from django.utils import timezone

start_date = timezone.datetime(2024, 1, 1, tzinfo=timezone.utc)
end_date = timezone.datetime(2024, 6, 30, tzinfo=timezone.utc)

# 先定义过滤后的工单查询集
filtered_tickets = CustomerTicket.objects.filter(date__range=(start_date, end_date))

# 预加载符合条件的工单,存到自定义属性里
customers = Customer.objects.prefetch_related(
    Prefetch(
        'customerticket',  # 对应Customer模型里的关联字段名
        queryset=filtered_tickets,
        to_attr='filtered_ticket'  # 自定义属性名,用来存过滤后的工单
    )
).all()

# 使用示例:遍历客户,提取工单或设为null
for customer in customers:
    # 因为是OneToOne,filtered_ticket要么是空列表,要么只有一个元素
    ticket = customer.filtered_ticket[0] if customer.filtered_ticket else None
    print(f"客户:{customer.name},工单:{ticket}")

注意事项

  • 一定要处理时区!用django.utils.timezone模块来定义日期,避免本地时间和数据库UTC时间不匹配导致的过滤错误
  • 因为是OneToOneField,每个客户最多对应一个工单,所以两种方案都能准确匹配,不用担心多个工单的情况
  • 方案二的预加载方式更适合数据量大的场景,能有效减少数据库查询次数

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

火山引擎 最新活动