在具有版本化数据的 Django 模型中获取条目的最新版本

问题描述 投票:0回答:1

我正在处理的应用程序有一个时间表,可以分配工作人员在不同的时间段在不同的地点工作。时间表通过

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)

每个时间块只能分配一个工人到一个位置。该位置由具有该工人和时间块的最新非空

ScheduleEntry
change_set.published_on
确定。

A

Worker
可能是未安排的(有
None
作为他们的位置)要么是因为在那个时间段内没有工作人员的任何计划条目,条目都链接到未发布的更改集,或者是最近发布的条目指定
null
作为
location
.

获取工作人员在特定时间段内当前发布的时间表位置很容易:

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

但是,我无法弄清楚如何执行查询以获取以下内容:

  • 工人的完整时间表,跨越所有时间段
  • 所有预定在特定时间段内在特定地点工作的工人

换句话说,我想要一个查询,该查询返回属于已发布更改集的所有计划条目,并且没有被具有更新的

change_set.published_on
值的同一 worker/time_block 对的后续条目覆盖。一旦有了它,我就可以使用过滤器进一步细化查询,以按位置、时间段或人员获取条目。

我想对查询应用

.distinct('worker', 'time_block')
,但是传递字段名称是 PostgreSQL 的唯一功能,我目前正在使用 SQLite。

这是可以用 SQL 和 Django ORM 高效表达的东西吗?

django django-orm
1个回答
0
投票

对于任何后来发现这个问题的人,这是我最终得出的解决方案:

from django.db.models import OuterRef, Exists

ScheduleEntry.objects.filter(
  change_set__published_on__isnull=False,
).exclude(
  Exists(
    ScheduleEntry.objects.filter(
      worker=OuterRef('worker'),
      time_block=OuterRef('time_block'),
      change_set__published_on__isnull=False,
      change_set__published_on__gt=OuterRef('change_set__published_on'),
    )
  )
)

外部查询首先过滤记录以仅包括那些属于已发布更改集的记录 (

change_set__published_on__isnull=False
)。如果内部结果为任何记录 (
.exclude
),则它会排除记录 (
Exists
)。

内部查询在模型中查找与外部查询 (

worker
) 具有相同
worker=OuterRef('worker')
的任何记录,相同的
time_block
,即已发布的更改集的一部分 (
.._isnull=False
) 和 最关键的是 是后来更改集的一部分 (
change_set__published_on__gt=OuterRef('change_set__published_on')
)。

实际上,它的作用是排除在后续更改集中被“覆盖”的条目,从而只保留每个条目的最新版本。

© www.soinside.com 2019 - 2024. All rights reserved.