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

如何在Django中获取版本化调度模型的最新已发布条目?

调度系统的最新已发布条目查询方案(兼容SQLite)

问题背景

我开发的应用包含一个调度系统,用于为工人分配不同时间段的工作地点,调度通过ChangeSet模型实现版本控制,每个ScheduleEntry关联一个ChangeSet。

模型定义

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

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

class TimeBlock(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()

class ChangeSet(models.Model):
    published_on = models.DateTimeField(null=True)

class ScheduleEntry(models.Model):
    change_set = models.ForeignKey(ChangeSet, on_delete=models.CASCADE)
    worker = models.ForeignKey(Worker, on_delete=models.CASCADE)
    time_block = models.ForeignKey(TimeBlock, on_delete=models.CASCADE)
    location = models.ForeignKey(Location, null=True, on_delete=models.CASCADE)

核心规则

每个工人在每个时间段只能被分配一个地点,由该工人和时间段对应的、拥有**最新非空change_set.published_on**的ScheduleEntry决定。工人未调度的情况包括:

  • 无对应时间段的条目
  • 所有条目关联未发布的变更集
  • 最新已发布条目location为null

单个工人单个时间段的查询逻辑很简单:

ScheduleEntry.objects.filter(
    change_set__published_on__isnull=False,
    worker=my_worker,
    time_block=my_time_block,
).order_by('-change_set__published_on').first()

但需要实现以下跨场景查询(需兼容SQLite,不能依赖PostgreSQL的多字段distinct特性):

  • 某工人全时间段的完整调度
  • 特定时间段内被分配到特定地点的所有工人

本质是要查询所有属于已发布变更集、且未被同工人/时间段对的后续(change_set.published_on更新)条目覆盖的ScheduleEntry。


解决方案

1. SQL原生查询思路

通过子查询找到每个(worker, time_block)对对应的最大published_on值,再关联原表筛选出匹配的条目:

SELECT se.*
FROM scheduleentry se
JOIN changeset cs ON se.change_set_id = cs.id
WHERE cs.published_on IS NOT NULL
AND (se.worker_id, se.time_block_id, cs.published_on) IN (
    SELECT se_inner.worker_id, se_inner.time_block_id, MAX(cs_inner.published_on)
    FROM scheduleentry se_inner
    JOIN changeset cs_inner ON se_inner.change_set_id = cs_inner.id
    WHERE cs_inner.published_on IS NOT NULL
    GROUP BY se_inner.worker_id, se_inner.time_block_id
)

2. Django ORM实现

利用Subquery和OuterRef实现上述逻辑,完全兼容SQLite:

from django.db.models import Subquery, OuterRef, Max

# 子查询:获取每个(worker, time_block)对的最新已发布时间
latest_published_subquery = ScheduleEntry.objects.filter(
    worker=OuterRef('worker'),
    time_block=OuterRef('time_block'),
    change_set__published_on__isnull=False
).annotate(
    latest_published=Max('change_set__published_on')
).values('latest_published')[:1]

# 主查询:筛选出匹配最新发布时间的已调度条目
latest_schedule_entries = ScheduleEntry.objects.filter(
    change_set__published_on__isnull=False,
    change_set__published_on=Subquery(latest_published_subquery)
)

基于结果的过滤示例

某工人全时间段的完整调度

worker_full_schedule = latest_schedule_entries.filter(worker=my_worker)

特定时间段内被分配到特定地点的所有工人

target_workers = latest_schedule_entries.filter(
    time_block__start_date__lte=target_end_date,
    time_block__end_date__gte=target_start_date,
    location=my_location
).values_list('worker', flat=True).distinct()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 02:47:37