#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 [email protected].
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.