#35677: Unexpected behaviour of Prefetch with queryset filtering on a through model -------------------------------------+------------------------------------- Reporter: David Glenck | Owner: (none) Type: Uncategorized | Status: closed Component: Database layer | Version: 5.1 (models, ORM) | Severity: Normal | Resolution: needsinfo Keywords: Prefetch, | Triage Stage: prefetch_related, many-to-many | Unreviewed Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Comment (by David Glenck):
Hi Natalia Thank you for pointing me to some related issues. I checked them and they refer to some behaviour I also referred to, but the issue I am pointing out is a different one. What I am trying to do is to optimize a repeating query of this shape (but of course more complex in reality) {{{#!python for subscriber in subscribers: subscriber.subscriptions.filter(status__is_active=True) }}} by prefetching the related objects like this: {{{#!python prefetched = Subscriber.objects.filter(pk__in=subscribers).prefetch_related( Prefetch( 'subscriptions', queryset=Subscription.objects.filter(status__is_active=True), to_attr='active_subscriptions' ) ) for subscriber in prefetched: prefetched[0].active_subscriptions }}} From the code above I would expect, that the prefetch gives the same results as my un-prefetched query. But it doesn't. This is because the first case, django does some magic internally, to combine my `.filter(status__is_active=True)`, with the internal filter to select subscriptions from this specific subscriber. Such that the result is, as if it would be a single filter (which is relevant in many-to-many relations). But in the case of the prefetch django doesn't do that magic internally and thus it returns a different result. So my proposal is to make the prefetched result behave the same as the non-prefetched one by modifying the internal behaviour of the prefetch query. Or at least give an option to do so. Because currently I have no clean way to instruct the prefetch to do what I want. I'm not sure if this is a bug or a feature request, because this specific case is not mentioned in the documentation, but I would argue that it is the expected behaviour. For illustration, this dirty workaround makes the prefetch return the result, that I would expect (but has undesired side-effects): {{{#!python class StickyQueryset(models.QuerySet): def _chain(self): self._sticky_filter = True return self class Subscription(models.Model): provider_name = models.CharField(max_length=255) objects = StickyQueryset.as_manager() }}} I tried looking deeper into the QuerySet code to see if I can propose some patch. But it's rather complex code in there. -- Ticket URL: <https://code.djangoproject.com/ticket/35677#comment:2> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/01070191529ed490-1a6a7289-f740-4196-b43f-ffb9fba3f30d-000000%40eu-central-1.amazonses.com.