Search code examples
djangodjango-querysetdjango-generic-views

modify a listview queryset to summarize a table containing columns with same value


I have 2 models; one is for material definition and the other is for stocks tracking. I need a stocks table because there will be same materials with different expiry date. I m using a django generic listview and want to modify queryset to display a summary list of materials quantities will be summed.

for expample :

stocks_table:

name    packing_details    expiry_date    quantity
milk    1lt boxes          11/11/2019     30
milk    1lt boxes          12/12/2019     40

after modifiying the queryset :

name    packing_details    quantity
milk    1lt boxes          70

is it possible with the generic listview or should i prepare a function based view ?

Models

class Material(models.Model):

    name = models.CharField(max_length=500)
    packing_details = models.CharField(max_length=500)
    material_unit = models.CharField(max_length=3)
class Stock(models.Model):
    material = models.ForeignKey(Material, on_delete=models.CASCADE)
    expiry_date = models.DateField()
    quantity = models.DecimalField(max_digits=10, decimal_places=2)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    date_created = models.DateField(default=timezone.now)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, default=1)

View

class StocksListView(LoginRequiredMixin, ListView):
    model = Stock
    context_object_name = 'stocks'

Template

            {% for stock in stocks %}
                <tr>
                    <td class="text-center">{{ stock.material.name }}</td>
                    <td class="text-center">{{ stock.material.packing_details }}</td>
                    <td class="text-center">{{ stock.quantity }}</td>
                    <td class="text-center">{{ stock.price }}</td>
                </tr>
            {% endfor %}

Solution

  • Wherever you do this, you actually need to flip the query; you need to get a list of Materials, and sum their stock quantities.

    So:

    from django.db.models import Sum
    
    Material.objects.annotate(quantity=Sum('stock__quantity')).filter(quantity__gt=0)
    

    You can set that directly as the queryset in the view:

    class StocksListView(LoginRequiredMixin, ListView):
        queryset = Material.objects.annotate...
    

    You'll need to update your template now that you're starting from Material instead of Stock.