Search code examples
pythondjangodjango-viewsdjango-templates

Return multiple values in Django Class-based View


I am working on a project for a Django course I am taking but currently struggling a bit with views.

In the project I created a View using ListView to display a list of products in my template. By using query_set I am able to get all the objects and return them to display all the products and their attributes in the template by using a for loop.

In the same query_set, I tried returning another variable that contains the total items in stock to display this data in the template as well, however, as soon as I add this variable to the return the template no longer receives the returned values.

This is the code I tried to return both values:

class ShopListing(ListView):
    template_name = "webshop/shop_listing.html"
    context_object_name = 'shop_listing'

    def get_queryset(self):
        #Get all products
        products = Product.objects.all()
        total_stock = products.aggregate(sum=Sum('stock'))['sum']
        return products, total_stock

In my template I added the value 'total_stock' as shown below but I get nothing, and even the values from 'products' stop working:

<p><strong>{{total_stock}}</strong> items are currently available</p>

If I remove 'total_stock' from the return everything goes back to normal.

If I print "total_stock" I can see the right value in the logs, but this cannot be used in my template so I wonder what is the right way to do this.

Will appreciate any guidance.


Solution

  • I suspect this is because of the machinery behind get_queryset(). By returning an additional value, you're actually returning a tuple to the view class methods that internally call get_queryset(). You can take a look at the Django source code for ListView and its related classes to see how they work with models and template context variables behind the scenes.

    Given your description, however, I think you want to extend the get_context_data() method instead:

    class ShopListing(ListView):
        template_name = "webshop/shop_listing.html"
        context_object_name = 'shop_listing'
        queryset = Product.objects.all()
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['total_stock'] = Product.objects.aggregate(sum=Sum('stock'))['sum']
            return context
    

    'total_stock' should be available as a template variable, along with the intended QuerySet.