Как написать запрос, чтобы получить значение find в json-поле в django

У меня есть json-поле в моей базе данных, которое похоже на

jsonfield = {'username':'chingo','reputation':'5'}

как я могу написать запрос, чтобы узнать, существует ли имя пользователя. что-то вроде

username = 'chingo'
query = User.objects.get(jsonfield['username']=username)

Я знаю, что указанный выше запрос неправильный, но я хотел знать, есть ли способ получить к нему доступ?

Ответ 1

Это использование несколько анти-шаблонов. Кроме того, его реализация не будет иметь регулярную производительность и, возможно, подвержена ошибкам.
Обычно не используйте 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 не являются слишком особенными (я пока не знаю какого-либо примера egde, возможно, кто-то может указать на него)
  • ваши данные jsonfield не повреждены (маловероятно)

На самом деле я работаю над редактируемым jsonfield и думаю о том, поддерживать ли такие операции. Отрицательное доказательство, как было сказано выше, похоже на черную магию, хорошо.

Ответ 2

Если вы используете пакет django-jsonfield, то это просто. Скажем, у вас есть такая модель:

from jsonfield import JSONField
class User(models.Model):
    jsonfield = JSONField()

Затем для поиска записей с определенным именем пользователя вы можете просто сделать это:

User.objects.get(jsonfield__contains={'username':username})

Ответ 3

Начиная с Django 1.9, вы можете использовать родной JSONField PostgreSQL. Это делает поиск JSON очень простым. В вашем примере этот запрос будет работать:

User.objects.get(jsonfield__username='chingo')

Если у вас установлена ​​более ранняя версия Django или вы используете библиотеку Django JSONField для совместимости с MySQL или что-то подобное, вы все равно можете выполнить свой запрос.

В последней ситуации jsonfield будет сохранен как текстовое поле и сопоставлен с dict при вводе в Django. В базе данных ваши данные будут сохранены следующим образом:

{"username":"chingo","reputation":"5"}

Поэтому вы можете просто искать текст. Ваш запрос в этом siutation будет выглядеть следующим образом:

User.objects.get(jsonfield__contains='"username":"chingo"')

Ответ 4

Если вы используете 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 как с обычным текстом, выглядят очень плохо. Итак, также я считаю, что вам нужна лучшая схема базы данных.

Ответ 5

Вот как я узнал, что решит вашу проблему:

search_filter = '"username":{0}'.format(username)
query = User.objects.get(jsonfield__contains=search_filter)

Надеюсь, что это поможет.

Ответ 6

2019 год. Как указывает @freethebees, теперь все просто:

User.objects.get(jsonfield__username='chingo')

Но, как уже упоминалось в примерах документации, вы можете выполнять глубокие запросы, а если json является массивом, вы можете использовать целое число для его индексации:

https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#querying-jsonfield

>>> 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

Ответ 7

Вы не можете этого сделать. Используйте обычные поля базы данных для структурированных данных, а не JSON-капли.

Если вам нужно искать данные JSON, рассмотрите возможность использования базы данных noSQL, такой как MongoDB.