是否可以通过将 hstore 值转换为 int
来过滤查询集?或 float
?
我遇到了一个问题,我们需要向现有数据模型添加更强大的查询。数据模型使用 HStoreField
存储大部分建筑数据,我们需要能够查询/过滤它们,一些值需要被视为数值。
但是,由于这些值被视为字符串,因此会逐个比较它们并导致不正确的查询。例如,'700' > '1000'
.
因此,如果我想查询 sqft 值在 700 到 1000 之间的所有项目,我会得到零结果,即使我可以清楚地看到有数百个项目的值在该范围内。如果我只查询 sqft 值 >= 700 的项目,我只会得到 sqft 值以 7、8 或 9 开头的结果。
我还尝试使用来自 django-pgjson
的 JsonField 进行测试。 (因为我们还没有在 Django 1.9 上),但它似乎有同样的问题。
设置
Django==1.8.9
django-pgjson==0.3.1 (for jsonfield functionality)
Postgres==9.4.7
模型.py
from django.contrib.postgres.fields import HStoreField
from django.db import models
class Building (models.Model):
address1 = models.CharField(max_length=50)
address2 = models.CharField(max_length=20, default='', blank=True)
city = models.CharField(max_length=50)
state = models.CharField(max_length=2)
zipcode = models.CharField(max_length=10)
data = HStoreField(blank=True, null=True)
示例数据
这是 hstore 字段中某些数据的示例。
address1: ...
address2: ...
city: ...
state: ...
zipcode: ...
data: {
'year_built': '1995',
'building_type': 'residential',
'building_subtype': 'single-family',
'bedrooms': '2',
'bathrooms': '1',
'total_sqft': '958',
}
返回错误结果的示例查询
queryset = Building.objects.filter(data__total_sqft__gte=700)
我试过玩弄
annotate
功能,看看我是否可以强制它转换为一个数值,但我没有运气让它工作。我总是收到一条错误消息,说我查询的字段不存在。这是我在其他地方找到的一个例子,它似乎不起作用。queryset = Building.objects.all().annotate(
sqft=RawSQL("((data->>total_sqft)::numeric)")
).filter(sqft__gte=700)
这导致此错误:
FieldError: Cannot resolve keyword 'sqft' into field. Choices are: address1, address2, city, state, zipcode, data
使此设置进一步复杂化的一件事是我们正在动态构建查询并使用
Q()
对象和/或它们在一起。因此,尝试做类似这样的事情,给定一个键、值和运算符类型(
gte
、 lte
、 iexact
):queryset.annotate(**{key: RawSQL("((%data->>%s)::numeric)", (key,)})
queries.append(Q(**{'{}__{}'.format(key, operator): value})
queries.filter(reduce(operator.and_, queries)
但是,即使只是让第一个查询工作而不动态构建它们,我也会很高兴。
我已经考虑过必须为具有明确定义的字段的建筑数据创建单独模型的可能性,但是在
data
中有超过 600 个键值对。商店。似乎将其更改为具体的数据模型将是设置和潜在维护的噩梦。
最佳答案
所以我遇到了一个非常相似的问题并最终使用了 Cast Function (Django > 1.10) 与 KeyTextTransform .
my_query =.query.annotate(as_numeric=Cast(KeyTextTransform('my_json_fieldname', 'metadata'), output_field=DecimalField(max_digits=6, decimal_places=2))).filter(as_numeric=2)
关于python - hstore或json数据的Django数字比较?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36782029/