1

i'm trying to prefetch related from parent model to chidren throught the related name, However the queryset in the template still hits the DB in PostgreSQL, my modelB modelC and ModelD all point towards modelA and when I overwrite the generic class based view queryset function it still doesnt affect the size of the query?? any clues ?

*MODEL
class ModelA(models.Model):
    title = models.Charfield(max_lenght=200, null=True, Blank=True)

class ModelB(models.Model):
    model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE, related_name="model_a_related")

*VIEW
class ModelAView(DetailView):
    model = ModelA

    def get_queryset(self):
        return super().get_queryset().prefetch_related('model_a_related')
  • 1
    `.prefetch_related` does *not* fetches the `ModelB`s in the same query, but in a second query. For a `DetailView`, it will not make an improvement: `.prefetch_related` is useful if you render a *set* of `ModelA`s, since then you prevent making a query *per* `ModelA` object to fetch the related `ModelB`s. – Willem Van Onsem Feb 12 '22 at 10:47

1 Answers1

1

.prefetch_related(…) [Django-doc] does not fetches the ModelBs in the same query, but in a second query where it fetches all the related ModelBs for the selected (filtered) ModelAs in bulk, this in contract to fetching it per ModelA object which would be the usual behavior.

For a DetailView [Django-doc], it will thus not make any improvement. In a DetailView you render a single item, and fetching the related ModelBs will, regardless whether it is done through .prefetch_related(…) or by accessing object.model_a_related.all() make one extra query.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Is there a way around to prefetch the data as I think it could be a usefull function for django – Drayen Dörff Feb 12 '22 at 10:52
  • 1
    @DrayenDörff: no, the reason `.prefetch_related(..)` was implemented that way is to minimize *bandwidth*: if that would be in the same query, it would produced a lot of duplicate data in the result, and this could eventually lead to hundreds of useless megabytes being transferred from the database to Django. – Willem Van Onsem Feb 12 '22 at 10:54
  • so that means that I could reverse the structure to have the modelA pointing to ModelB, that will save a lot of bandwidth, and save me some RAM and CPU usage ? – Drayen Dörff Feb 12 '22 at 11:01
  • 1
    @DrayenDörff: if you would use `ModelB.objects.select_related('model_a').filter(model_a__pk=42)`, it will actually result in trouble: indeed, for each record in the result set, it will use exactly the same data for the `model_a` fields, this is why `.prefetch_related` uses another query, to avoid making a query where the same data is *repeated* per record. – Willem Van Onsem Feb 12 '22 at 11:03
  • ok so I do a manytomany from modelA to ModelB – Drayen Dörff Feb 12 '22 at 11:06
  • 1
    @DrayenDörff: but the modeling should not be done to optimize queries, but to model the data as it is supposed to be. A many-to-many field means that each `ModelA` object can have zero, one or more related `ModelB`s, and that a `ModelB` object can have zero, one or more related `ModelA` objects. – Willem Van Onsem Feb 12 '22 at 11:14