doableware/djongo

How can I search Empty JSONField?

ghoul-ipg opened this issue · 2 comments

One line description of the issue

I have a Data JsonField that defaults to {}

from djongo import models
class Resume(models.Model):
    name = models.CharField(max_length=255)
    data = models.JSONField(default=dict)

I want to get all the resumes whoes data is {}

Python script

resume = Resume.objects.filter(data={}).all()

Traceback

Traceback (most recent call last):
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 857, in parse
    return handler(self, statement)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 933, in _select
    return SelectQuery(self.db, self.connection_properties, sm, self._params)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 116, in __init__
    super().__init__(*args)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 62, in __init__
    self.parse()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 152, in parse
    self.where = WhereConverter(self, statement)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\converters.py", line 27, in __init__
    self.parse()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\converters.py", line 119, in parse
    self.op = WhereOp(
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\operators.py", line 475, in __init__
    self._statement2ops()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\operators.py", line 428, in _statement2ops
    op = self._token2op(tok, statement)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\operators.py", line 395, in _token2op
    op = CmpOp(tok, self.query)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\operators.py", line 517, in __init__
    self._field_ext, self._constant = next(iter(self._constant.items()))
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\cursor.py", line 51, in execute
    self.result = Query(
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 784, in __init__
    self._query = self.parse()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\sql2mongo\query.py", line 885, in parse
    raise exe from e
djongo.exceptions.SQLDecodeError:

        Keyword: None
        Sub SQL: None
        FAILED SQL: SELECT "mm_resume"."id", "mm_resume"."name", "mm_resume"."data" FROM "mm_resume" WHERE "mm_resume"."data" = %(0)s ORDER BY "mm_resume"."id" ASC LIMIT 1
        Params: ({},)
        Version: 1.3.6

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\cursor.py", line 59, in execute
    raise db_exe from e
djongo.database.DatabaseError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\EDZ\PycharmProjects\testmongo\mysite\manage.py", line 22, in <module>
    main()
  File "C:\Users\EDZ\PycharmProjects\testmongo\mysite\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\core\management\__init__.py", line 425, in execute_from_command_line
    utility.execute()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\core\management\__init__.py", line 419, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\core\management\base.py", line 373, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\core\management\base.py", line 417, in execute
    output = self.handle(*args, **options)
  File "C:\Users\EDZ\PycharmProjects\testmongo\mysite\mm\management\commands\aa.py", line 11, in handle
    re = Resume.objects.filter(data={}).first()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\models\query.py", line 682, in first
    for obj in (self if self.ordered else self.order_by('pk'))[:1]:
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\models\query.py", line 280, in __iter__
    self._fetch_all()
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\models\query.py", line 1354, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\models\query.py", line 51, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\models\sql\compiler.py", line 1202, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\backends\utils.py", line 99, in execute
    return super().execute(sql, params)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\backends\utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\EDZ\PycharmProjects\testmongo\pvenv\lib\site-packages\djongo\cursor.py", line 59, in execute
    raise db_exe from e
django.db.utils.DatabaseError

I tried to modify CmpOp to implement my results, or do you have any other methods?

class CmpOp(_Op):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._identifier = SQLToken.token2sql(self.statement.left, self.query)
        self._is_empty = False
        if isinstance(self.statement.right, Identifier):
            raise SQLDecodeError('Join using WHERE not supported')

        self._operator = OPERATOR_MAP[self.statement.token_next(0)[1].value]
        index = re_index(self.statement.right.value)

        self._constant = self.params[index] if index is not None else None
        if isinstance(self._constant, dict):
            if not self._constant:
                self._field_ext = None
                self._is_empty = True
            else:
                self._field_ext, self._constant = next(iter(self._constant.items()))
        else:
            self._field_ext = None

    def negate(self):
        self.is_negated = True

    def evaluate(self):
        pass

    def to_mongo(self):
        field = self._identifier.field
        if self._field_ext:
            field += '.' + self._field_ext
        if self._is_empty:
            value = {}
        else:
            value = {self._operator: self._constant}
        if not self.is_negated:
            return {field: value}
        else:
            return {field: {'$not': value}}

What if you remove ".all()" ?