Джанго постгрес поле Json с цифровыми клавишами
У меня есть модель с Postgres JSON Field.
class MyModel(models.Model):
data = JSONField(null=True)
тогда я делаю:
m1 = MyModel.objects.create(data={'10':'2017-12-1'})
m2 = MyModel.objects.create(data={'10':'2018-5-1'})
Я хочу запросить все MyModel, чей ключ "10" начинается с "2017", поэтому я хочу написать:
MyModel.objects.filter(data__10__startswith='2017')
Проблема заключается в том, что число 10 интерпретируется как целое число, и поэтому в сгенерированном запросе оно рассматривается как индекс списка, а не как ключ. Есть ли способ решить это? (кроме написания необработанных запросов).
Это сгенерированный запрос:
SELECT "systools_mymodel"."id", "systools_mymodel"."data" FROM "systools_mymodel" WHERE ("systools_mymodel"."data" ->> 10)::text LIKE '2017%' LIMIT 21;
И я хочу, чтобы 10 были указаны (что дало бы мне правильный ответ).
Спасибо!
1 ответ
Очень хакерское решение (используйте на свой страх и риск, протестировано под Django 2.0.5, аннулирует гарантию...):
# patch_jsonb.py
from django.contrib.postgres.fields.jsonb import KeyTransform
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 %s %%s)" % (lhs, self.nested_operator), [
key_transforms] + params
try:
int(self.key_name)
except ValueError:
if self.key_name.startswith("K") and self.key_name[1:].isnumeric():
lookup = "'%s'" % self.key_name[1:]
else:
lookup = "'%s'" % self.key_name
else:
lookup = "%s" % self.key_name
return "(%s %s %s)" % (lhs, self.operator, lookup), params
def patch():
KeyTransform.as_sql = as_sql
Использование:
Добавьте это к нижней части вашего
settings.py
:import patch_jsonb patch_jsonb.patch()
Вместо
__123__
использование поисков__K123__
поиски - в верхнем регистреK
будет удален этим патчем:MyModel.objects.filter(data__K10__startswith='2017')
И попробуйте не использовать числа в качестве ключей объекта jsonb...