Skip to content
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

IN lookup #394

Closed
maxtepkeev opened this issue Mar 25, 2016 · 9 comments
Closed

IN lookup #394

maxtepkeev opened this issue Mar 25, 2016 · 9 comments

Comments

@maxtepkeev
Copy link

Hi,

I'm using django-filter with django-rest-framework, this one doesn't work, it just returns nothing:

import django_filters
from rest_framework import filters

from ..models import MyModel


class MyModelFilter(filters.FilterSet):
    my_field = django_filters.CharFilter(lookup_expr='in')

    class Meta:
        model = MyModel

But this one does and works as expected:

from django_filters import filters as df_filters
from rest_framework import filters

from ..models import MyModel


class CharInFilter(df_filters.BaseInFilter, df_filters.CharFilter):
    pass


class MyModelFilter(filters.FilterSet):
    my_field = CharInFilter()

    class Meta:
        model = MyModel

Is this a normal and expected behaviour or am I doing something wrong here ? Thanks.

@rpkilby
Copy link
Collaborator

rpkilby commented Mar 25, 2016

Hi @maxtepkeev. Yes - this is the expected behavior. Filters are not 'expression aware' and will not alter behavior according to their lookup_expr.

You can either manually create the filter class as you've done in the second example, or you can automatically generate filters with the dictionary style syntax for Meta.fields. Internally, it does the same thing as in your example.

eg,

class MyModelFilter(Filters.FilterSet):
    class Meta:
        model = MyModel
        fields = {
            'my_field': ['exact', 'in', ...],
        }

@maxtepkeev
Copy link
Author

Hi @rpkilby

Thanks for reply.

IMHO that is not very obvious from the documentation, so maybe you can add some more information about that in the docs.

Also, the second example with Meta.fields doesn't work for me for some reason.

@carltongibson
Copy link
Owner

@maxtepkeev Any PRs on the docs are very welcome!

I think the underlying issue is the CharFilter is only expecting (receiving?) a single value, not a list; that comes from how the widget maps data from the GET QueryDict — All of that is Django Forms internals, which isn't that clear to many people. We probably need to have some background reading to explain the mechanics...

@rpkilby
Copy link
Collaborator

rpkilby commented Mar 29, 2016

@carltongibson I'll try to work on this later tonight. Could rework this into a section on common problems and/or theory.

@maxtepkeev Here are the docs on mixing the BaseInFilter with other filter types, however it's not exactly obvious on how to get there. eg, if you were to search the docs on how to correctly use CharFilter with lookup_expr='in', you probably wouldn't find that section.
Are you still having problems with the Meta.fields syntax? Maybe post model/filter code and the traceback?

@maxtepkeev
Copy link
Author

@rpkilby Yes, it was hard to find, but I've read this section and after that I implemented my current working solution, i.e.:

from django_filters import filters as df_filters
from rest_framework import filters

from ..models import MyModel


class CharInFilter(df_filters.BaseInFilter, df_filters.CharFilter):
    pass


class MyModelFilter(filters.FilterSet):
    my_field = CharInFilter()

    class Meta:
        model = MyModel

Meta.fields still doesn't work for me, it doesn't produce any tracebacks, errors or anything else, it just returns empty result set, this is how I'm trying to use it:

from rest_framework import filters

from ..models import MyModel


class MyModelFilter(filters.FilterSet):
    class Meta:
        model = MyModel
        fields = {
            'my_field': ['in'],
        }

As I said earlier, I'm using django-filter with django-rest-framework, I'm using ?my_field=Option1,Option2 syntax in URL which correctly works with my current solution but doesn't work with Meta.fields.

@rpkilby
Copy link
Collaborator

rpkilby commented Mar 29, 2016

Ah, you should be filtering with ?my_field__in=Option1,Option2. This makes more sense when you have multiple lookups. eg,

class ProductFilter(filterset.Filter):
    class Meta:
        model = Product
        fields = {'price': ['exact', 'in', 'lt', 'gt'], }

Would generate price, price__in, price__lt, and price__gt filters.

@maxtepkeev
Copy link
Author

Of course, my bad, it works now.

But if I don't like the __in part, the only option is to use the custom class like I'm doing at the moment, right ?

@rpkilby
Copy link
Collaborator

rpkilby commented Mar 29, 2016

Yep, and that's fine if you only have the one filter for that field. If you have multiple filters for a field though, you'll need to use some naming strategy to differentiate between them. eg, price__in, price__lt, price__gt.

@maxtepkeev
Copy link
Author

Yes, that makes sense. Thanks. I have no more questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants