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:
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.