#35317: Add the possibility to do prefetches for only a subset of instances -------------------------------------+------------------------------------- Reporter: Laurent Lyaudet | Owner: nobody Type: New feature | Status: closed Component: Database layer | Version: 5.0 (models, ORM) | Severity: Normal | Resolution: wontfix Keywords: | Triage Stage: | Unreviewed Has patch: 1 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 -------------------------------------+------------------------------------- Comment (by Laurent Lyaudet):
I did a second PR https://github.com/django/django/pull/18003 adding a post_prefetch_callback argument to Prefetch. Here is a redacted production code example that I could develop with the corresponding patch in my package django-monkey-patches. I doubt you can find an efficient way and requiring around the same amount of code to do the same thing without these features. {{{#!python class OModelSerializer(...): @staticmethod def enhance_queryset( query_set, prefix: str = "", c_id: Optional[CId] = None, ): query_set = SomeMixin1.enhance_queryset(query_set, prefix) def ventilate_ps_by_c_id( lookup, done_queries, ): prefetch_to = lookup.prefetch_to prefetch_before = get_previous_prefetch_to(prefetch_to) for obj in prefetch_before: if hasattr(obj, "needed_ps"): if not hasattr(obj, "needed_p_by"): obj.needed_p_by = {} for obj2 in obj.needed_ps: obj.needed_p_by[obj2.c_id] = obj2 return query_set.prefetch_related( f"{prefix}p2", Prefetch( f"{prefix}s", post_prefetch_callback=create_post_prefetch_callback_add_backward_multiple( retrieve_forward_cache_callback=lambda o: [o.s] if o.s_id else [], backward_cache_name="current_o_ancestors", ), ), Prefetch( f"{prefix}c2", post_prefetch_callback=create_post_prefetch_callback_add_backward_multiple( retrieve_forward_cache_callback=lambda o:[o.c2] if o.c2_id else [], backward_cache_name="current_order_ancestors", ), ), Prefetch( f"{prefix}s__ps", queryset=( P.objects.filter(c_id=c_id) if c_id else P.objects.all() ), to_attr="needed_ps", filter_callback=lambda p: hasattr(p, "_prefetched_objects_cache") and p._prefetched_objects_cache.get("current_order_ancestors") and any( map( lambda o: o.c2_id is not None, p._prefetched_objects_cache.get( "current_o_ancestors" ).values(), ) ), post_prefetch_callback=ventilate_ps_by_c_id, ), Prefetch( f"{prefix}c2__u", queryset=C2U.objects.filter(p2_id__isnull=False) .distinct("c2_id") .prefetch_related( "p2", Prefetch( f"p2__ps", queryset=( P.objects.filter(c_id=c_id) if c_id else P.objects.all() ), to_attr="needed_ps", post_prefetch_callback=ventilate_ps_by_c_id, ), ), to_attr="needed_u", filter_callback=lambda c: ( hasattr(c2, "_prefetched_objects_cache") and c2._prefetched_objects_cache.get("current_o_ancestors") and any( map( lambda o: o.c2_id is not None and o.s_id is None, c._prefetched_objects_cache.get( "current_o_ancestors" ).values(), ) ) ), ), ) class DModelSerializer(...): ... @staticmethod def enhance_queryset( query_set, prefix: str = "", c_id: Optional[CId] = None, ): query_set = SomeMixin2.enhance_queryset( query_set, f"{prefix}l__", ) query_set = OModelSerializer.enhance_queryset( query_set, f"{prefix}l__", c_id=c_id, ) query_set = query_set.prefetch_related( f"{prefix}l__s2", f"{prefix}l__p3", f"{prefix}l2__s3__u", Prefetch( f"{prefix}l__r1", queryset=R1.objects.filter( d_id=F("o__s2__d_id"), r2__s4=SOME_CONSTANT, ).select_related("r2"), to_attr="pertinent_r3", ), ) return query_set }}} -- Ticket URL: <https://code.djangoproject.com/ticket/35317#comment:7> 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/0107018e633aa5c0-d920df18-91dd-414c-9ce5-1ce85c620840-000000%40eu-central-1.amazonses.com.