django - неподдерживаемый поиск для JSONField или объединение в поле не разрешено

У меня есть поле Json в моих моделях как -

class Product(models.Model):
    ...
    detailed_stock           = JSONField(load_kwargs={'object_pairs_hook': collections.OrderedDict},default=dict)

У меня есть значения в моей базе данных, такие как -

{
  "total":0,
  "5[1]":0
}

Я пытаюсь отфильтровать объекты с total = 0, для этого я пробовал -

Product.objects.filter(detailed_stock__total = 0) но выдает ошибку -

Unsupported lookup 'total' for JSONField or join on the field not permitted.

согласно документации разрешен следующий код.

это полная трассировка-

Traceback (most recent call last):
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\core\handlers\exception.py", line 35, in inner
    response = get_response(request)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\core\handlers\base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\views\generic\base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\braces\views\_access.py", line 102, in dispatch
    request, *args, **kwargs)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\views\generic\base.py", line 89, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\views\generic\list.py", line 142, in get
    self.object_list = self.get_queryset()
  File "c:\Users\lenovo\Desktop\My_Django_Stuff\bekaim\accounts\views.py", line 142, in get_queryset
    queryset = Product.objects.filter(detailed_stock__total = 0)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\query.py", line 836, in filter
    return self._filter_or_exclude(False, *args, **kwargs)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\query.py", line 854, in _filter_or_exclude
    clone.query.add_q(Q(*args, **kwargs))
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\sql\query.py", line 1253, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\sql\query.py", line 1271, in _add_q
    current_negated, allow_joins, split_subq)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\sql\query.py", line 1277, in _add_q
    split_subq=split_subq,
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\sql\query.py", line 1215, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\sql\query.py", line 1069, in build_lookup
    lhs = self.try_transform(lhs, name)
  File "C:\Users\lenovo\AppData\Local\conda\conda\envs\myDjangoEnv\lib\site-packages\django\db\models\sql\query.py", line 1115, in try_transform
    (name, lhs.output_field.__class__.__name__))
django.core.exceptions.FieldError: Unsupported lookup 'total' for JSONField or join on the field not permitted.
[31/Dec/2018 16:13:37] "GET /accounts/product-list/?clean=outofstock HTTP/1.1" 500 150927

Я искал в Интернете, но не смог найти решение, пожалуйста, помогите.


person Pankaj Sharma    schedule 31.12.2018    source источник


Ответы (2)


Я думаю, вы используете django-jsonfield, как указано load_kwargs={'object_pairs_hook': collections.OrderedDict} вместо django.contrib.postgres.fields.JSONField .

django-jsonfield предназначен для баз данных, которые не предлагают собственный тип dict, и основан на простом TextField. Когда вы обращаетесь к значению поля с помощью product.detail_stock, внутренне сохраненное str преобразуется в dict с помощью json.loads() по самому полю. Следовательно, вы можете использовать только такие операции, как icontains и contains, для запроса этого поля.

Если вы используете postgres в качестве базы данных, вы можете в полной мере воспользоваться преимуществами django.contrib.postgres.fields.JSONField, как указано в документации. Но вы должны импортировать правильный JSONfield с помощью django.contrib.postgres.fields import JSONField.

Существует решение для mysql (пакет django-mysql).

person escaped    schedule 31.12.2018
comment
хорошо, есть проблема, так что, если я сейчас изменю поле, оно будет перенесено без проблем? - person Pankaj Sharma; 31.12.2018
comment
Сомневаюсь, поскольку оба поля имеют разную внутреннюю структуру. Но вы можете попробовать и сообщить, если это сработает. - person escaped; 31.12.2018
comment
В противном случае вам придется перенести свои данные: 1. добавьте новый JSONField (postgres) с другим именем, 2. используйте перенос данных, чтобы скопировать данные в новое поле, 3. удалить исходное поле, 4. переименовать новое поле в detailed_stock. Это можно сделать за одну миграцию. Если вам нужна помощь, не стесняйтесь спрашивать. - person escaped; 31.12.2018
comment
Можно ли использовать содержимое для модуля django-jsonfield? Я пытался, но это не работает. - person jack; 14.10.2019
comment
django-jsonfield использует CharField внутри. Если вы используете __contains для запроса этого поля, вы должны быть очень точными с точки зрения пробелов и кавычек, например. __contains="'foo':3" не будет соответствовать {"foo": 3}. - person escaped; 17.10.2019

Если вы используете Django и использовали:

from json_field import JSONField

Тогда вы не сможете воспользоваться поиском SQL. Как упоминалось выше, JSONField переопределяет только TextField. Он проверяет формат JSON и выводит в виде строки.

class JSONField(models.TextField):
    """ Stores and loads valid JSON objects. """

Вместо этого используйте

from django.db import models
data = models.JSONField(null=True)
person Abhishek    schedule 01.09.2020