hstore或json数据的Django数字比较?
Posted
技术标签:
【中文标题】hstore或json数据的Django数字比较?【英文标题】:Django numeric comparison of hstore or json data? 【发布时间】:2016-08-15 09:19:16 【问题描述】:是否可以通过将 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
models.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:无法将关键字“sqft”解析为字段。选项有: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
hstore 中有超过 600 个键值对。似乎将其更改为具体的数据模型将是设置和维护的一场噩梦。
【问题讨论】:
我已经能够通过升级 Django 并使用 1.9 中的内置JSONField
而不是 django-pgjson
来使查询工作,因为它使用 jsonb
而不是 json
数据库字段.但是,使用标准 json 字段似乎仍然可以做到这一点。
total_sqft 周围的单引号?如: RawSQL("((data->>'total_sqft')::numeric)")。也许也没有内部括号:RawSQL("(data->>'total_sqft'::numeric)")。我不使用 HStore,但这就是 PostgreSQL 将它用于 JSON 的方式。
【参考方案1】:
所以我遇到了一个非常相似的问题,最终将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)
【讨论】:
以上是关于hstore或json数据的Django数字比较?的主要内容,如果未能解决你的问题,请参考以下文章
Django HStore:如何覆盖键值模型字段的 __getattr__ 和 __setattr__
PostgreSQL 9.2 - 将 TEXT json 字符串转换为 json/hstore 类型