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

Allow to override retrieving of a queryset in a FilterSet #740

Closed
Alexx-G opened this issue Jun 21, 2017 · 4 comments
Closed

Allow to override retrieving of a queryset in a FilterSet #740

Alexx-G opened this issue Jun 21, 2017 · 4 comments

Comments

@Alexx-G
Copy link

Alexx-G commented Jun 21, 2017

The title may be a little bit confusing. It would be nice to have a generic filter method which is called everytime queryset is retrieved and filtering for fields is applied. Yeah, I can override qs property, firstly get filtered queryset and then apply prefetches. But it's not clear if this may have some side-effects and the data passed to filter is safe to access.

There's my use case.
I'm filtering a queryset by a M2M relationship (as in queryset.filter(items__field="foo")). However I want to get prefetched items filtered by that field as well.

In other words my filter looks like this:

# In my filterset
def filter_items_by_field(self, queryset, name, value):
        queryset = queryset.all().filter(
            items__field=value,
        )
        prefetched_items = Prefetch(
            'items',
            Item.objects..filter(
                field=value,
            ),
        )
        return queryset.prefetch_related(prefetched_items)

# In my vieset
def get_queryset(self):
        queryset = super().get_queryset()
        # This should be applied everytime
        prefetched_items = Prefetch(
            'items',
            Item.objects..filter(
                another_field=some_value,
            ),
        )
        return queryset.prefetch_related(prefetched_items)

A single filter like this works as expected. However, I may have several filter_items_by_* filters + I need to apply same filtering for queryset from prefetch for all filters. And multiple filters aren't a problem, because they're mutually exclusive in my case. But a filter + generic will cause an exception.

The point is that I can apply only one prefetch for the same lookup. So, in my case I'll simply get an exception.

I have a temporary workaround for this problem: all filter_items_by_* performs mandatory filtering on prefetch.
And in filter_queryset (after filtering was applied), if items aren't prefetched (what is bad since I'm inspecting queryset protected attrs), I apply prefetch with the mandatory filtering. But there should be a better way to deal with situations like this.

I hope my example is clear enough.

@rpkilby
Copy link
Collaborator

rpkilby commented Aug 15, 2017

Hi @Alexx-G. I think this could be possible with some coordination between the filterset and relevant filter classes. Essentially, the filter would append a Prefetch instance to its parent filterset. FilterSet.qs would then simply call prefetch_related when appropriate.

That said, what's the use case for this? I would argue that there are likely more appropriate places to handle prefetching.

@Alexx-G
Copy link
Author

Alexx-G commented Aug 15, 2017

I think this could be possible with some coordination between the filterset and relevant filter classes.

I've already solved my issue by overriding qs property, but again, it's not obvious and it's not documented. In other words, I can't be sure that some internal changes in the base class won't affect my filterset (ok, I've pinned version, but anyway..)

That said, what's the use case for this? I would argue that there are likely more appropriate places to handle prefetching.

I believe I described above my use case. It doesn't make sense to separate filtering and prefetching, because prefetching depends on filters. And if I separate them, I'll have to duplicate same checks for filters.

In other words, if there was a description of the public contract of the qs property or a documented hook for it, this would improve customization of the filter set.

@rpkilby
Copy link
Collaborator

rpkilby commented Oct 24, 2017

Hi @Alexx-G. A 2.0 release is still a ways out, but there are going to be some changes to the API that specifically address this question. In short,

  • You will want to override the .filter_queryset() method. The .qs attribute will basically be responsible for calling .filter_queryset() and caching its result.
  • You can get the filter values for prefetching from self.form.cleaned_data.

@Alexx-G
Copy link
Author

Alexx-G commented Oct 24, 2017

Thanks a lot for your effort!

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

2 participants