Как написать запрос, чтобы получить значение поиска в поле JSON в Django
У меня есть поле JSON в моей базе данных, которая похожа
jsonfield = {'username':'chingo','reputation':'5'}
Как я могу написать запрос, чтобы я мог найти, если имя пользователя существует. что-то вроде
username = 'chingo'
query = User.objects.get(jsonfield['username']=username)
Я знаю, что приведенный выше запрос неверен, но я хотел знать, есть ли способ получить к нему доступ?
6 ответов
Это использование несколько анти-шаблон. Кроме того, его реализация не будет иметь регулярной производительности и, возможно, подвержена ошибкам.
Обычно не используйте jsonfield, когда вам нужно просмотреть поля. Используйте способ, который обеспечивает СУБД или MongoDB(который внутренне работает на более быстром BSON), как указал Даниэль.
Из-за детерминированности формата JSON вы можете достичь этого, используя contains
(regex
имеет проблемы при работе с несколькими '\'
и даже медленнее), я не думаю, что это хорошо использовать username
таким образом, так что используйте name
вместо:
def make_cond(name, value):
from django.utils import simplejson
cond = simplejson.dumps({name:value})[1:-1] # remove '{' and '}'
return ' ' + cond # avoid '\"'
User.objects.get(jsonfield__contains=make_cond(name, value))
Это работает до тех пор, пока
- Jsonfield с использованием той же утилиты дампа (
simplejson
Вот) name
а такжеvalue
не слишком особенные (я не знаю ни одного случая, когда-либо, возможно, кто-то мог бы указать на это)- Ваши данные jsonfield не повреждены (хотя вряд ли)
На самом деле я работаю над редактируемым jsonfield и думаю о том, поддерживать ли такие операции. Негативное доказательство, как сказано выше, похоже на какую-то черную магию.
Если вы используете пакет django-jsonfield, то это просто. Скажем, у вас есть такая модель:
from jsonfield import JSONField
class User(models.Model):
jsonfield = JSONField()
Затем, чтобы искать записи с определенным именем пользователя, вы можете просто сделать это:
User.objects.get(jsonfield__contains={'username':username})
Начиная с Django 1.9, вы можете использовать собственный JSONField для PostgreSQL. Это делает поиск JSON очень простым. В вашем примере этот запрос будет работать:
User.objects.get(jsonfield__username='chingo')
Если у вас более старая версия Django или вы используете библиотеку Django JSONField для совместимости с MySQL или чем-то подобным, вы все равно можете выполнить свой запрос.
В последней ситуации jsonfield
будет сохранен как текстовое поле и сопоставлен с диктовкой при переносе в Django. В базе данных ваши данные будут храниться так
{"username":"chingo","reputation":"5"}
Поэтому вы можете просто искать текст. Ваш запрос в этой ситуации будет:
User.objects.get(jsonfield__contains='"username":"chingo"')
2019: как указывает @freethebees, теперь это так просто, как:
User.objects.get(jsonfield__username='chingo')
Но, как уже упоминалось в примерах документации, вы можете делать глубокие запросы, и если json является массивом, вы можете использовать целое число для его индексации:
https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/
>>> Dog.objects.create(name='Rufus', data={
... 'breed': 'labrador',
... 'owner': {
... 'name': 'Bob',
... 'other_pets': [{
... 'name': 'Fishy',
... }],
... },
... })
>>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})
>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>
>>> Dog.objects.filter(data__owner__name='Bob')
<QuerySet [<Dog: Rufus>]>
>>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
<QuerySet [<Dog: Rufus>]>
Хотя это для postgres, я считаю, что он работает так же и в других БД, таких как MySQL
Если вы используете PostgreSQL, вы можете использовать raw sql для решения проблемы.
username = 'chingo'
SQL_QUERY = "SELECT true FROM you_table WHERE jsonfield::json->>'username' = '%s'"
User.objects.extra(where=[SQL_EXCLUDE % username]).get()
где you_table
это имя таблицы в вашей базе данных.
Любые методы, когда вы работаете с JSON, например, с простым текстом - выглядят очень плохо. Итак, я также думаю, что вам нужна лучшая схема базы данных.
Вы не можете сделать это. Используйте обычные поля базы данных для структурированных данных, а не двоичные объекты JSON.
Если вам нужен поиск по данным JSON, рассмотрите возможность использования базы данных noSQL, такой как MongoDB.
Вот способ, который я обнаружил, который решит вашу проблему:
search_filter = '"username":{0}'.format(username)
query = User.objects.get(jsonfield__contains=search_filter)
Надеюсь это поможет.