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

Fallback behavior for the callable filter #72

Open
selimt opened this issue Nov 19, 2018 · 3 comments
Open

Fallback behavior for the callable filter #72

selimt opened this issue Nov 19, 2018 · 3 comments

Comments

@selimt
Copy link

selimt commented Nov 19, 2018

Hi I have a callable filter that handles a custom lookup that I implemented:

class StatusFilter(CallableFilter):
    @form_field_for_filter(forms.CharField())
    def filter_has_any_keys_for_django(self, queryset, spec):
        value = spec.value.split(',')
        if spec.is_negated:
            return queryset.exclude(status__has_any_keys=value)
        else:
            return queryset.filter(status__has_any_keys=value)

    @form_field_for_filter(forms.CharField())
    def filter_contains_for_django(self, queryset, spec):
        if spec.is_negated:
            return queryset.exclude(status__contains=spec.value)
        else:
            return queryset.filter(status__contains=spec.value)

And it works great. The issue is that if the callable filter doesn't support other types of lookups, I want it to fall back to the default way of handling the filters, so for example if I try to specify a query parameter like ".../?status=["complete","succeeded"] then I get an error:

AssertionError: StatusFilter was not provided form_field parameter in initialization (e.g. StatusFilter(form_field=CharField)) and form_field was not provided for the lookup. If the lookup is a custom filter callable you should provide form_field by using @form_field_for_filter decorator. If the lookup is a normal lookup, then please either provide form_field parameter or overwrite get_form_field().

Is there a mechanism for this?

Thanks
-Selim

@miki725
Copy link
Owner

miki725 commented Nov 19, 2018

not any simple way at the moment

@selimt
Copy link
Author

selimt commented Nov 19, 2018

That's ok, it was as simple as adding the following:

    @form_field_for_filter(forms.CharField())
    def filter_exact_for_django(self, queryset, spec):
        value = json.loads(spec.value)
        f = queryset.filter if not spec.is_negated else queryset.exclude
        return f(status=value)

@tbitai
Copy link

tbitai commented Jun 24, 2020

In order to solve this problem, I wrote FallbackCallableFilter:

class FallbackCallableFilter(CallableFilter):
    def get_spec(self, config):
        spec = super(CallableFilter, self).get_spec(config)
        try:
            spec.filter_callable = self._get_filter_method_for_lookup(spec.lookup)
        except AttributeError:
            pass
        return spec

Perhaps this could be part of the project?

Note that @selimt's solution is not complete, as there are many other lookups besides __exact (__icontains, __in etc.).

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