doableware / djongo

Django and MongoDB database connector
https://www.djongomapper.com
GNU Affero General Public License v3.0
1.86k stars 351 forks source link

Filtering on BooleanField causes Error #655

Open Axbry opened 1 year ago

Axbry commented 1 year ago

One line description of the issue

There's an error when filtering on BooleanField.

Python script

. My model is simple:

from django.db import models
from djongo.models import ObjectIdField

class TmpModel(models.Model):
    _id = ObjectIdField()
    is_deleted = models.BooleanField(default=False)

When I run in shell filter command:

>>> TmpModel().save()   
>>> TmpModel(is_deleted=True).save() 
>>> TmpModel.objects.filter(is_deleted=False).all() 

I got an error:

Traceback

(0.000) QUERY = 'SELECT "solutions_tmpmodel"."_id", "solutions_tmpmodel"."is_deleted" FROM "solutions_tmpmodel" WHERE NOT "solutions_tmpmodel"."is_deleted" LIMIT 21' - PARAMS = (); args=(); alias=default Traceback (most recent call last): File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\query.py", line 857, in parse return handler(self, statement) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\query.py", line 933, in _select return SelectQuery(self.db, self.connection_properties, sm, self._params) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\query.py", line 116, in init super().init(*args) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\query.py", line 62, in init self.parse() File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\query.py", line 152, in parse self.where = WhereConverter(self, statement) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\converters.py", line 27, in init self.parse() File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\converters.py", line 119, in parse self.op = WhereOp( File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\operators.py", line 476, in init self.evaluate() File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\operators.py", line 465, in evaluate op.evaluate() File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\operators.py", line 258, in evaluate self.rhs.negate() AttributeError: 'NoneType' object has no attribute 'negate'

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

Traceback (most recent call last): File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\cursor.py", line 51, in execute self.result = Query( File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\sql2mongo\query.py", line 784, in init self._query = self.parse() File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\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 "solutions_tmpmodel"."_id", "solutions_tmpmodel"."is_deleted" FROM "solutions_tmpmodel" WHERE NOT "solutions_tmpmodel"."is_deleted" LIMIT 21
    Params: ()
    Version: 1.3.6

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

Traceback (most recent call last): File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\backends\utils.py", line 89, in _execute return self.cursor.execute(sql, params) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\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 "", line 1, in File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\models\query.py", line 370, in repr data = list(self[: REPR_OUTPUT_SIZE + 1]) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\models\query.py", line 394, in iter self._fetch_all() File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\models\query.py", line 1866, in _fetch_all self._result_cache = list(self._iterable_class(self)) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\models\query.py", line 87, in iter results = compiler.execute_sql( File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\models\sql\compiler.py", line 1398, in execute_sql cursor.execute(sql, params) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\django\db\backends\utils.py", line 103, in execute return super().execute(sql, params) s.py", line 89, in _execute return self.cursor.execute(sql, params) File "C:\Users\user\AppData\Local\pypoetry\Cache\virtualenvs\test-task-YJIxAxLW-py3.10\lib\site-packages\djongo\cursor.py", line 59, in execute raise db_exe from e django.db.utils.DatabaseError

abstatic commented 1 year ago

I am also facing the similar issue, cannot use filtering or fetching if I use a boolean field.

YusufBerki commented 1 year ago

We discussed this in issue #465. You can simply use this:

TmpModel.objects.filter(is_deleted__in=[False]).all() 

Not this:

TmpModel.objects.filter(is_deleted=False).all() 

I explained the reason for the error with this comment in the issue.

I'm still facing the same problem with filtering boolean expressions. As far as I can see the problem is in converting the django code to SQL.

When you call boolean filter like:

User.objects.filter(is_active=True)

Generated this:

... from user where is_active

But actually it should be like this

... from user where is_active == true

@debu999's solution still works. This is because it converts the boolean equality wrong as above but converts the "is in" filter correct.

User.objects.filter(is_active__in=[True])