Get related Model foreignkey (in addition to the ManyToMany) with prefetch_related(model_SET).all()

Viewed 29

With prefetch_related, I retrieve the list of my different warehouses stock like this :

Model Product

[nothing special]

Model Warehouse

[nothing special]

Model SstStock

class SstStock(models.Model):
    warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
    product = models.ManyToManyField(Produit)
    qty = models.IntegerField()
    last_update = models.DateTimeField(default=timezone.now)

views.py

class ProductListView(LoginRequiredMixin, ListView):
    queryset = Product.objects.prefetch_related('sststock_set').all()
    context_object_name = "produits"
    paginate_by = 10
    template_name = 'products/produits.html'

    def get_context_data(self, *args, **kwargs):
        context = super(ProductListView, self).get_context_data(
            *args, **kwargs)
        context['title'] = 'Produits'
        return context

Template

{% for produit in produits %}
    {{ produit.sku}}<br>
    {% for sst in produit.sststock_set.all %}
        <span>{{ sst.warehouse.code }} - {{sst.qty}} - {{sst.qty}}</span>
    {% endfor %}
{% endfor %}

But when I get the information related to the warehouse eg. sst.warehouse.code in template, the number of queries explodes. (already 36 queries with a pagination of only 10 products)

Is there a way to add warehouse in prefetch_related in the view ?

2 Answers

You can use a Prefetch object [Django-doc]:

class ProductListView(LoginRequiredMixin, ListView):
    queryset = Product.objects.prefetch_related(
        Prefetch('sststock_set', SstStock.objects.select_related('warehouse'))
    ))
    # …

Note: Django's DateTimeField [Django-doc] has a auto_now=… parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when updating the object, and mark it as non-editable (editable=False), such that it does not appear in ModelForms by default.

Well, as I couldn't find the way to proceed with serializer for getting my sststock_set, the only solution by the time was to rebuild the data json in the view.

data = list()
        for product in products:
            item = {}
            item['sku'] = product.sku
            item['pk'] = product.pk
            item['famille'] = product.famille.nom
            item['etat'] = product.etat.etat
            # print(product.nom)
            item['mageid'] = product.mageid
            item['adresse'] = product.adresse
            item['fournisseur'] = product.fournisseur.nom
            item['mini'] = product.mini
            item['pua'] = float(product.pua)
            item['pta'] = float(product.pta)
            item['nom'] = product.nom
            item['puv'] = float(product.puv)
            item['ptv'] = float(product.ptv)
            item['cau'] = float(product.cau)
            item['cau_cli'] = float(product.cau_cli)
            item['maxsst2'] = product.maxsst2

            item['sststock'] = list()
            for sst in product.sststock_set.all():
                item['sststock'].append(
                    {'sst_code': sst.warehouse.code, 'sst_id': sst.warehouse.pk, 'qty': sst.qty})
            data.append(item)
        data = json.dumps(data)
        
        return HttpResponse(data, content_type="application/json")
Related