Hi everyone,
I’ve a question about best practices around prefetching. Let’s assume a basic model like the following (untested so there might be typos):
class A(models.Model):
name = models.CharField(max_length=30)
included = models.BooleanField(default=False)
bees = models.ForeignKey("B", on_delete=models.CASCADE, related_name="reverse_as")
class B(models.Model):
name = models.CharField(max_length=50)
def get_included_as(self):
return self.reverse_as.filter(included=True)
For reference I’m using DRF, so the “problem” happens at serialization time.
Now in my views I want to prefetch As to avoid cascading queries for each Bs something akin to:
B.objects.filter(...).prefetch_related(Prefetch("reverse_as", A.objects.all().filter(included=True)))
Now if my serializer (which I want to be generic as much as possible) does just B.get_included_as django will hit again the DB despite the query being prefetched, that’s expected and documented behavior, because I do filtering on the resulting queryset.
My solution is to use to_attr on the Prefetch object and have my serializer access the field conditionnally something like:
B.objects.filter(...).prefetch_related(Prefetch("reverse_as", A.objects.all().filter(included=True), to_attr="prefetched_as"))
if has_attr(obj, 'prefetched_as'):
return obj.prefetched_as
else:
# defer to the generic accessor :
return obj.get_included_as()
Now my question is, the pattern is quite simple and easy to follow, but is there a better / more canonical way of dealing with this?
Thanks in advance.