我从 Django 的文档中获取了以下示例,除了替换添加了一个键“99”:
>>> Dog.objects.create(name='Rufus', data={
... 'breed': 'labrador',
... 'owner': {
... 'name': 'Bob',
... 'other_pets': [{
... 'name': 'Fishy',
... }],
... },
... })
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', '99': 'FINDME',})
>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>
Run Code Online (Sandbox Code Playgroud)
我希望以下内容也返回“梅格”狗:
Dog.objects.filter(data__99='FINDME')
Run Code Online (Sandbox Code Playgroud)
然而,似乎因为我的键是一个整数,Django 没有正确处理这个问题。我如何在python jsonfields中有字符串的整数键?
这是记录在案的行为:
如果键是整数,它将被解释为数组中的索引查找。
如果您希望查询的键与另一个查找的名称发生冲突,请改用 jsonfield.contains 查找。
所以建议的解决方案是使用jsonfield.contains:
Dog.objects.filter(data__contains={'99': 'FINDME'})
Run Code Online (Sandbox Code Playgroud)
无论如何,我建议您避免在 json 字段中使用数字键,因为使用该contains方法您无法执行startswith和其他类似的查找(请参阅此类似问题),例如Dog.objects.filter(data__99__startswith='FIND').
看来没有什么好的选择。这是 django/contrib/postgres/fields/jsonb.py 的片段:
def as_sql(self, compiler, connection):
key_transforms = [self.key_name]
previous = self.lhs
while isinstance(previous, KeyTransform):
key_transforms.insert(0, previous.key_name)
previous = previous.lhs
lhs, params = compiler.compile(previous)
if len(key_transforms) > 1:
return "{} #> %s".format(lhs), [key_transforms] + params
try:
int(self.key_name)
except ValueError:
lookup = "'%s'" % self.key_name
else:
lookup = "%s" % self.key_name
return "%s -> %s" % (lhs, lookup), params
Run Code Online (Sandbox Code Playgroud)
由此看来,它试图将每个键都转换为整数,并在可能的情况下使用它作为键。
您可以使用以下技巧来按照您想要的方式进行查询:
def jsonb_integer_keys_to_str(qs, key):
return qs.model.objects.raw(qs.query.__str__().replace('-> {}'.format(key), "-> '{}'".format(key)))
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
jsonb_integer_keys_to_str(Dog.objects.filter(data__99='FINDME'), 99)
Run Code Online (Sandbox Code Playgroud)
该解决方案过于具体,但在这种情况下可行。它所做的就是修改 postgres sql 并将引号放在正确的位置。
| 归档时间: |
|
| 查看次数: |
1039 次 |
| 最近记录: |