I’m wondering if we can make it simpler to prefetch relations recursively.
I have trees modeled with a self-referring foreign key (“adjacency list” trees), like this model in the Django test suite I’ve edited to have a related_name
of “children”.
class Node(models.Model):
num = models.IntegerField(unique=True)
parent = models.ForeignKey(
"self", models.SET_NULL, to_field="num", null=True, related_name="children"
)
I’ve been prefetching the child relationships like this:
Node.objects.prefetch_related("children__children__children")
which works great for a known depth of 3. But when the depth of the tree isn’t known, you can do the following: specify a depth (e.g. 50) that is way past what you’re likely to need, and Django is smart enough to stop doing queries once the depth is exhausted:
def test_recursive_fk_prefetch_related(self):
node1 = Node.objects.create(num=42)
node2 = Node.objects.create(num=43, parent=node1)
with self.assertNumQueries(3):
self.assertSequenceEqual(
Node.objects.prefetch_related("__".join(["children"] * 50)).all(),
[node1, node2],
)
That works great if a depth of 10 is the biggest likely depth, and 50 would be vanishingly rare.
But what if 100 becomes the biggest likely depth, and 1000 would be vanishingly rare? Use 1000 as the magic number?
I’m wondering if we couldn’t add something to Django to be able to replace:
Node.objects.prefetch_related("__".join(["children"] * 50))
with
Node.objects.prefetch_related("children*")
Of course this could be problematic for users who have cycles in their trees (graphs?) But if this is opt-in behavior, I’m not so worried about that.
Doing the magic number feels like a trick, and it makes it look like Django is doing 50 queries.
I also have cases where I need to do things like:
Node.objects.prefetch_related(
"children__other",
"children__other__children__other",
)
So the ability to do even this would be helpful:
Node.objects.prefetch_related(
models.Prefetch("children__other", recursive=True),
)
How are folks prefetching their self-referring foreign key relationships? I haven’t looked in depth detail at the various libraries for tree querying in Django, but core Django is already meeting my needs with the caveat that I’d like to be able to prefetch children to arbitrary depth.