django中查询(获取)RangeField的上界

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

我想通过 django queryset 获取 RangeField 的上限。

当您可以访问 python 对象时,

my_model.size_range.upper
就可以工作。不在查询引擎内部,无法使用
F
When
Case
...

class MyModel(models.Model):
    size_range = IntergerRangeField()

MyModel.objects.all().annotate(new_upper=F('size_range__upper') + 1)
FieldError: Unsupported lookup 'upper' for IntegerRangeField or join on the field not permitted.

有什么想法吗?

python django postgresql django-models psycopg2
3个回答
4
投票

我找到了一个半解决方案:

from django.db.models.functions import Upper

MyModel.objects.all().annotate(
      upper=Upper('size_range')
  ).annotate(
      new_upper=F('upper') + 1
  )

虽然感觉很笨拙,但至少有用

如果有人更了解吗?我确信可以直接查询原始值。


0
投票

你想用它做什么?您也许可以使用

endswith

MyModel.objects.filter(size_range__endswith=some_value))

0
投票

使用 django,您可以注册 自定义查找

IntegerRangeField.register_lookup(MyCustomLookup)

但是您无法直接在

Upper
RangeField
上注册
IntegerRangeField
,因为默认情况下循环使用与
output_field
相同的字段(例如:您想要的类型不是
IntegerRangeField
而是
IntegerField
) 。
output_field
必须明确。

使用

IntegerRangeField
自定义查找
Upper
如下所示:

from django.contrib.postgres.fields import IntegerRangeField
from django.db.models.functions import Upper


class IntegerRangeUpper(Upper):
    output_field = IntegerRangeField.base_field()


IntegerRangeField.register_lookup(IntegerRangeUpper)


MyModel.objects.all().annotate(
   new_upper=F('size_range__upper') + 1
)

由于在所有类型的范围字段上使用此功能可能很有用,并且通过查找手动注册范围字段的所有排列会非常重复,因此该过程可以推广。

此代码使用

base_field
作为
output_field
创建基于原始查找类的新查找类,并将它们注册到字段中。

import itertools

from django.contrib.postgres.fields import IntegerRangeField, BigIntegerRangeField, DateRangeField, DateTimeRangeField, DecimalRangeField
from django.db.models.functions import Lower, Upper


def register_range_lookup(
    field, lookup_class
):
    class CustomLookup(lookup_class):
        output_field = field.base_field()

    field.register_class_lookup(CustomLookup)    


for range_field, lookup_class in itertools.product(
    [
        IntegerRangeField,
        BigIntegerRangeField,
        DateRangeField,
        DateTimeRangeField,
        DecimalRangeField,
    ],
    [Lower, Upper],
):
    register_range_lookup(range_field, lookup_class)

此外,

__lower
__upper
现在可以像这样用于过滤:

# Gets all instances where the lower bounds are greater than 5
MyModel.objects.all().filter(
    size_range__lower__gt=5
)
© www.soinside.com 2019 - 2024. All rights reserved.