-
Notifications
You must be signed in to change notification settings - Fork 755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NullBooleanField and None value #522
Comments
Hi @GuillaumeCisco - it seems like there are three issues here:
A magic value such as |
I think the bulk of this was covered by #519. @GuillaumeCisco please review that. If there is a specific test case that you think should be covered could you open a PR adding that and we can review. Thanks. |
Thank you @carltongibson and thank you too @rpkilby The NullBooleanField is working now with django rest framework with this configuration: CHOICES = (
(None, "OFF"),
(True, "YES"),
(False, "NO")
)
class MyModel(models.Model):
is_solved = models.NullBooleanField(choices=CHOICES)
choices = (
(True, "YES"),
(False, "NO")
)
class MyModelFilter(filters.FilterSet):
is_solved = ChoiceFilter(null_label='OFF', choices=choices)
class Meta:
model = MyModel
fields = ('is_solved',)
class MyModelViewSet(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = MyModelFilter Note the difference between the choices tuples. |
Hello, I encountered something very interesting today regarding NullBooleanField and the empty ('', 'None') value for filtering null values in db.
For the record, I use django rest framework.
Here is my experience:
I create a django model:
And in django rest framework, I declare my View:
With this, I have a filter on field
is_solved
with django rest framework.The filter use a select widget with label/values:
As described here : https://github.com/carltongibson/django-filter/blob/develop/django_filters/widgets.py#L103
When I use this filter, if I select
Unknown
, everything is returned... so nothing is filtered...What I wanted is to have only objects with
is_solved
set tonull
in db.Furthermore, I wanted to change the way
is_solved
is displayed, so I 've made a little modification on my Model.New model:
With this modification, The filter in django rest framework gives me correct Select Widget, but it now uses the ChoiceField, with its own widget.
It's also make more sense, as now I have a selectBox when creating a Model instead of a text input.
But when I select
OFF
for filtering, the url set a query_parameter as?is_solved=
:/It works well with True and False anyway.
So for making it works with django rest framework, I changed my choices to:
Note
'None'
instead ofNone
. And it's ok, I now have a query parameter?is_solved=None
but now, nothing is returned with this filter... The list is empty...
Made me put my hands in the django_filters code :)
The key is in this part of the code:
https://github.com/carltongibson/django-filter/blob/develop/django_filters/filters.py#L172
This little piece of code do the filtering.
And I've found something very very interesting with the dkango QuerySet behaviour.
One part of the important lines are :
The query is returned non filtered if we have an empty value, which is
[], (), u'', {}, None
But our value is
'None'
so it's okay, all the precedent code did not transform the'None'
value toNone
. But using theNullBooleanField
withoutchoices
does something totally different as the field is not considered as a ChoiceField :code from django core:
Now things get really really interesting...
Take a look at this line :
It does the filtering to pass to django core db Queryset.
We can translate it to:
This operation will return an empty queryset...
It will produce a sql query with
is_solved = None
But if we test :
It correctly returns only the instances with
null
values in db.It will produce a sql query with
is_solved IS NULL
This is the exact same thing to test:
However,
'True'
and'False'
values does not have this problem. The transcription is correct by Django.We could think of overriding the lookup_epxr of our filter by
isnull
but our filter will not work with theTrue
andFalse
values...At this point, I really don't know how to handle this behavior, django bug ? django filters missing something ?
Anyway, I've been able to make it works by rewriting the
filter
function of django filters:This looks like a hack and it does not please me for now...
If someone is interested on thinking on this issue I will be glad to hear it! :D
For now, any thoughts on this modification?
Right now, I think I will use an
IntegerField
with a choices option for not having to use a forked version of django filters... as I think it's not a django filters issue a the beginning :)Thanks,
The text was updated successfully, but these errors were encountered: