如何在 Django 中创建引用两个相关模型的注释
How to create an annotation in Django that references two related models
当一个相关对象上的字段值小于另一个相关对象上的字段值时,我正在尝试向 True/False 查询集添加注释。
这里有一些模型作为例子:
class RobotManager(models.Manager):
queryset = super(RobotManager, self).get_queryset()
queryset = queryset.annotate(canteen_empty=UNKNOWN CODE)
return queryset
class Robot(models.Model):
# Has some other unrelated stuff
objects = RobotManager()
class CanteenLevel(models.Model):
time = models.DateTimeField()
robot = models.ForeignKey("SomeApp.Robot")
gallons = models.IntegerField()
class RobotConfiguration(models.Model):
time = models.DateTimeField()
robot = models.ForeignKey("SomeApp.Robot")
canteen_empty_level = models.IntegerField()
对于以上模型,随着机器人的Configuration 或CanteenLevel 的变化,我们创建新的记录并保存历史记录。
我想做的是向机器人查询集添加注释,说明机器人的食堂是否被认为是空的(机器人的最新 CanteenLevel.gallons 小于机器人的最新 Configuration.canteen_empty_level)。
目的是允许使用 QuerySet 中的注释进行这样的语句:
bad_robots = Robot.objects.filter(canteen_empty=True)
我在注释中尝试过这样的事情:
canteen_empty=ExpressionWrapper(CanteenLevel.objects.filter(robot=OuterRef('pk')).order_by('-time').values('gallons')[:1] <= RobotConfiguration.objects.filter(robot=OuterRef('robot')).order_by('-time').values('canteen_empty_level')[:1], output_field=models.BooleanField))
但显然不允许使用“<=”运算符。
我也试过这个:
canteen_empty=Exists(CanteenLevel.objects.filter(robot=OuterRef('pk')).order_by('-time').values('gallons')[:1].filter(gallons__lte=Subquery(RobotConfiguration.objects.filter(robot=OuterRef('robot')).order_by('-time').values('canteen_empty_level')[:1]))))
但是你不能在取一个 QuerySet 的切片后进行过滤。
如有任何帮助,我们将不胜感激!
这里可以做两个注解:
from django.db.models import Subquery, OuterRef
latest_gallons = <b>Subquery(</b>CanteenLevel.objects.filter(
robot=OuterRef('pk')
).order_by('-time').values('gallons')[:1]<b>)</b>
latest_canteen = <b>Subquery(</b>RobotConfiguration.objects.filter(
robot=OuterRef('pk')
).order_by('-time').values('canteen_empty_level')[:1]<b>)</b>
然后我们可以先用这些注释Robot
对象,然后过滤:
from django.db.models import <b>F</b>
Robot.objects.annotate(
latest_gallons=latest_gallons,
latest_canteen=latest_canteen
).filter(<b>latest_gallons__lte=F('latest_canteen')</b>)
这将构造一个如下所示的查询:
SELECT robot.*,
(SELECT U0.gallons
FROM canteenlevel U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1) AS latest_gallons,
(SELECT U0.canteen_empty_level
FROM robotconfiguration U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1) AS latest_canteen
FROM robot
WHERE
(SELECT U0.gallons
FROM canteenlevel U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1
) <= (
SELECT U0.canteen_empty_level
FROM robotconfiguration U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1
)
但是请注意,如果 Robot
没有相关的 CanteenLevel
或 RobotConfiguration
(其中之一,或两者),那么 Robot
将 不被包含在查询集中。
当一个相关对象上的字段值小于另一个相关对象上的字段值时,我正在尝试向 True/False 查询集添加注释。
这里有一些模型作为例子:
class RobotManager(models.Manager):
queryset = super(RobotManager, self).get_queryset()
queryset = queryset.annotate(canteen_empty=UNKNOWN CODE)
return queryset
class Robot(models.Model):
# Has some other unrelated stuff
objects = RobotManager()
class CanteenLevel(models.Model):
time = models.DateTimeField()
robot = models.ForeignKey("SomeApp.Robot")
gallons = models.IntegerField()
class RobotConfiguration(models.Model):
time = models.DateTimeField()
robot = models.ForeignKey("SomeApp.Robot")
canteen_empty_level = models.IntegerField()
对于以上模型,随着机器人的Configuration 或CanteenLevel 的变化,我们创建新的记录并保存历史记录。
我想做的是向机器人查询集添加注释,说明机器人的食堂是否被认为是空的(机器人的最新 CanteenLevel.gallons 小于机器人的最新 Configuration.canteen_empty_level)。
目的是允许使用 QuerySet 中的注释进行这样的语句:
bad_robots = Robot.objects.filter(canteen_empty=True)
我在注释中尝试过这样的事情:
canteen_empty=ExpressionWrapper(CanteenLevel.objects.filter(robot=OuterRef('pk')).order_by('-time').values('gallons')[:1] <= RobotConfiguration.objects.filter(robot=OuterRef('robot')).order_by('-time').values('canteen_empty_level')[:1], output_field=models.BooleanField))
但显然不允许使用“<=”运算符。
我也试过这个:
canteen_empty=Exists(CanteenLevel.objects.filter(robot=OuterRef('pk')).order_by('-time').values('gallons')[:1].filter(gallons__lte=Subquery(RobotConfiguration.objects.filter(robot=OuterRef('robot')).order_by('-time').values('canteen_empty_level')[:1]))))
但是你不能在取一个 QuerySet 的切片后进行过滤。
如有任何帮助,我们将不胜感激!
这里可以做两个注解:
from django.db.models import Subquery, OuterRef
latest_gallons = <b>Subquery(</b>CanteenLevel.objects.filter(
robot=OuterRef('pk')
).order_by('-time').values('gallons')[:1]<b>)</b>
latest_canteen = <b>Subquery(</b>RobotConfiguration.objects.filter(
robot=OuterRef('pk')
).order_by('-time').values('canteen_empty_level')[:1]<b>)</b>
然后我们可以先用这些注释Robot
对象,然后过滤:
from django.db.models import <b>F</b>
Robot.objects.annotate(
latest_gallons=latest_gallons,
latest_canteen=latest_canteen
).filter(<b>latest_gallons__lte=F('latest_canteen')</b>)
这将构造一个如下所示的查询:
SELECT robot.*,
(SELECT U0.gallons
FROM canteenlevel U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1) AS latest_gallons,
(SELECT U0.canteen_empty_level
FROM robotconfiguration U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1) AS latest_canteen
FROM robot
WHERE
(SELECT U0.gallons
FROM canteenlevel U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1
) <= (
SELECT U0.canteen_empty_level
FROM robotconfiguration U0
WHERE U0.robot_id = robot.id
ORDER BY U0.time DESC
LIMIT 1
)
但是请注意,如果 Robot
没有相关的 CanteenLevel
或 RobotConfiguration
(其中之一,或两者),那么 Robot
将 不被包含在查询集中。