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

Default filtering when no filter parameters passed in request.GET #322

Closed
andrius-senulis opened this issue Nov 6, 2015 · 6 comments
Closed

Comments

@andrius-senulis
Copy link

Dear all,

Is there an option to set the default filter field and value to use if no parameter that I define in the Meta.fields has been found in the request object?

If there isn't such an option, what would you suggest as the best way to do it?

Regards,
Andrius

@andrius-senulis andrius-senulis changed the title Default filter Default filtering when no filters specified Nov 6, 2015
@andrius-senulis andrius-senulis changed the title Default filtering when no filters specified Default filtering when no parameters passed in request.GET Nov 6, 2015
@andrius-senulis andrius-senulis changed the title Default filtering when no parameters passed in request.GET Default filtering when no filter parameters passed in request.GET Nov 6, 2015
@rpkilby
Copy link
Collaborator

rpkilby commented Feb 19, 2016

Hi @andrius-senulis. django-filter is built on top of regular django forms, so this question can be boiled down into "How do I provide default field values for bound forms?" Per this SO answer, you can add a clean_<field_name> method to your form in order to provide a default value. Unfortunately, the underlying form class isn't directly exposed, so you can't subclass it and add that method (see edit). That said, filters have an underlying form field, so you could subclass the field and override its clean() method. This is a little cumbersome. eg,

class DecimalDefaultField(forms.DecimalField):
    def clean(self, value):
        if value is None:
            return 4.0
        return super(DecimalDefaultField, self).clean(value)

class NumberDefaultFilter(filters.NumberFilter):
    field_class = DecimalDefaultField

class MyFilterSet(FilterSet):
    some_field = NumberDefaultFilter(name='some_field')
    ...

An easier method would be to just inspect the incoming data and set a default value.

def your_view(request):
    data = request.GET.copy()
    data.setdefault('some_field', 'some_value')

    f = YourFilterSet(data, queryset=YourModel.objects.all())
    ...

edit:
You actually are able to provide a base form to the FilterSet.Meta, which is then subclassed internally. So, clean_<field name> is possible.

class MyForm(forms.Form):
    clean_some_field(self, value):
        ...

class MyFilterSet(FilterSet):
    class Meta:
        model = MyModel
        form = MyForm
        fields = ['some_field']

@nspo
Copy link

nspo commented Apr 27, 2017

I use a FilterView. Overriding get_filterset_kwargs works for me:

class MyFilterView(FilterView):
    filterset_class = filters.MyFilter
    # ...
    def get_filterset_kwargs(self, filterset_class):
        kwargs = super(MyFilterView, self).get_filterset_kwargs(filterset_class)
        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        return kwargs

Edit: When using e.g. pagination, this is not applied (b/c data is not None). Something like this might work:

        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        elif "is_very_interesting" not in kwargs["data"]:
            kwargs["data"] = kwargs["data"].copy()
            kwargs["data"]["is_very_interesting"] = False

@jcushman
Copy link

Using __init__ worked for me. (This is with djangorestframework-filters, but I think is the same as vanilla django-filter):

class MyFilter(filters.FilterSet):
    foo = ...

    def __init__(self, data, *args, **kwargs):
        if not data.get('foo'):
            data = data.copy()
            data['foo'] = 'bar'
        super().__init__(data, *args, **kwargs)

@elmcrest
Copy link

the method with __init__ isn't recommended and the workaround documented in the link didn't work for me ... https://django-filter.readthedocs.io/en/master/guide/tips.html#using-initial-values-as-defaults
get_filterset_kwargs in the FilterView worked for me.

@rpkilby
Copy link
Collaborator

rpkilby commented Oct 22, 2019

the method with __init__ isn't recommended

Providing default form/filter values in general is not recommended in that it's a bad practice that can have confusing/adverse effects. Implementing via __init__ or whatever other method is fine (given that you're okay with the effects).

@Real-Gecko
Copy link

I use a FilterView. Overriding get_filterset_kwargs works for me:

class MyFilterView(FilterView):
    filterset_class = filters.MyFilter
    # ...
    def get_filterset_kwargs(self, filterset_class):
        kwargs = super(MyFilterView, self).get_filterset_kwargs(filterset_class)
        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        return kwargs

Edit: When using e.g. pagination, this is not applied (b/c data is not None). Something like this might work:

        if kwargs["data"] is None:
            kwargs["data"] = {"is_very_interesting": False}
        elif "is_very_interesting" not in kwargs["data"]:
            kwargs["data"] = kwargs["data"].copy()
            kwargs["data"]["is_very_interesting"] = False

You made my day!

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

7 participants