Django 过滤具有两个值的属性,更喜欢一个的结果
Django filter on attribute with two values, preferring the result of one
这是一个奇怪的问题,提前致歉。我在 Django Rest 中有一个看起来像这样的模型:
class BaseModel(models.Model):
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Foo(BaseModel):
barId = models.ForeignKey(Bar, unique=False)
fizzId = models.ForeignKey(Fizz, unique=False)
buzzId = models.IntegerField(unique=False)
value = models.TextField()
我有一个 ViewSet 需要 return 具有给定 {request_barId, request_buzzId, lastUpdateDate} 的所有 Foos 的列表。这很简单,
foobar = Foo.objects.filter(
buzzId=request_buzzId,
modified_date__gt=request_lastUpdateDate,
barId=request_barId)
问题来了。 buzzId 有一个默认值,即指定的 buzzId 需要覆盖的 base list,替换 base 列表中的实例。这就是我有点迷路的地方。我有一个解决方案,但我觉得它不是特别优雅,而且会有一种方法可以做到这一点。这是我进行叠加的代码:
base_foobar = Foo.objects.filter(
buzzId=base_buzzId,
modified_date__gt=request_lastUpdateDate,
barId=request_barId).exclude(
fizzId__in=[o.fizzId for o in foobar])
result = foobar | base_foobar
这看起来真的很糟糕。有没有办法清理它?
编辑:为了澄清,假设元组列表 { 1, 0, '01-01-1970' } 表示基集 (buzzId: 0),returns 列表包含 fizzIds { 1, 2, 3, 10 } 的对象。假设元组 { 1, 1, '01-01-1970' } 表示一些 buzzId 对一组完整字符串的请求。如果我们说我们的 buzzId 为 1(称之为 augment)与 Foos 匹配 fizzIds { 2, 10, 15, 20 },那么我们的结果集应该看起来像
{ (base) 1, (augment) 2, (base) 3, (augment) 10, (augment) 15, (augment) 20 }
这样就清除了吗?
您可以使用 Q
组合成一条语句:
result = (Foo.objects
.filter(
Q(
modified_date__gt=request_lastUpdateDate,
barId=request_barId
)
&
(
Q(buzzId=request_buzzId)
|
(
Q(buzzId=base_buzzId)
&
~Q(fizzId__in=[o.fizzId for o in foobar])
)
)
)
.order_by( '-buzzId' if request_buzzId < base_buzzId else 'buzzId')
)[0] # fetch first result only
另外,以后请格式化你所有的代码。它不一定像我一样,但它肯定有助于阅读你的问题。
这是一个奇怪的问题,提前致歉。我在 Django Rest 中有一个看起来像这样的模型:
class BaseModel(models.Model):
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Foo(BaseModel):
barId = models.ForeignKey(Bar, unique=False)
fizzId = models.ForeignKey(Fizz, unique=False)
buzzId = models.IntegerField(unique=False)
value = models.TextField()
我有一个 ViewSet 需要 return 具有给定 {request_barId, request_buzzId, lastUpdateDate} 的所有 Foos 的列表。这很简单,
foobar = Foo.objects.filter(
buzzId=request_buzzId,
modified_date__gt=request_lastUpdateDate,
barId=request_barId)
问题来了。 buzzId 有一个默认值,即指定的 buzzId 需要覆盖的 base list,替换 base 列表中的实例。这就是我有点迷路的地方。我有一个解决方案,但我觉得它不是特别优雅,而且会有一种方法可以做到这一点。这是我进行叠加的代码:
base_foobar = Foo.objects.filter(
buzzId=base_buzzId,
modified_date__gt=request_lastUpdateDate,
barId=request_barId).exclude(
fizzId__in=[o.fizzId for o in foobar])
result = foobar | base_foobar
这看起来真的很糟糕。有没有办法清理它?
编辑:为了澄清,假设元组列表 { 1, 0, '01-01-1970' } 表示基集 (buzzId: 0),returns 列表包含 fizzIds { 1, 2, 3, 10 } 的对象。假设元组 { 1, 1, '01-01-1970' } 表示一些 buzzId 对一组完整字符串的请求。如果我们说我们的 buzzId 为 1(称之为 augment)与 Foos 匹配 fizzIds { 2, 10, 15, 20 },那么我们的结果集应该看起来像
{ (base) 1, (augment) 2, (base) 3, (augment) 10, (augment) 15, (augment) 20 }
这样就清除了吗?
您可以使用 Q
组合成一条语句:
result = (Foo.objects
.filter(
Q(
modified_date__gt=request_lastUpdateDate,
barId=request_barId
)
&
(
Q(buzzId=request_buzzId)
|
(
Q(buzzId=base_buzzId)
&
~Q(fizzId__in=[o.fizzId for o in foobar])
)
)
)
.order_by( '-buzzId' if request_buzzId < base_buzzId else 'buzzId')
)[0] # fetch first result only
另外,以后请格式化你所有的代码。它不一定像我一样,但它肯定有助于阅读你的问题。