如何基于分类在HTML表格展示Django Stock模型数据
Django按分类分组展示库存项解决方案
需求说明
Stock模型中每个库存项归属一个分类,需提取唯一分类,将对应分类的库存项展示在独立HTML表格中,并在表格上方显示分类名称作为标题。
现有模型(无需修改)
# models.py class Stock(models.Model): user = models.ForeignKey(User, on_delete = models.SET_NULL, null = True) part_No = models.CharField(max_length=100, null=True) item_name = models.CharField(max_length=100, null=True) category = models.CharField(max_length=100, null=True) unit = models.CharField(max_length=50, null=True) balance_bd = models.IntegerField(default='0', null = True) received = models.IntegerField(default='0', null = True) issued = models.IntegerField(default='0', null=True) unit_price = models.DecimalField(max_digits=20, decimal_places=2, null=True) obsolete = models.BooleanField(default=False, null=True)
修改后的视图函数
# views.py from itertools import groupby from django.db.models import F from django.shortcuts import render def stock(request): # 按分类排序,确保分组逻辑生效 stocks = Stock.objects.order_by('category').annotate( # 计算模板中需要的衍生字段 total_bal=F('balance_bd') + F('received'), tally_card_bal=F('total_bal') - F('issued'), total_price=F('tally_card_bal') * F('unit_price') ) # 按分类分组,生成{分类名称: 库存项列表}的字典 grouped_stocks = {} for category, items in groupby(stocks, key=lambda x: x.category): grouped_stocks[category] = list(items) # 计算所有库存项的总价总和 sum_total_price = sum( stock.total_price for stock in stocks if stock.total_price is not None ) context = { 'grouped_stocks': grouped_stocks, 'sumTotalPrice': sum_total_price } return render(request, 'base/stock.html', context)
修改后的HTML模板
<!-- base/stock.html --> <div class="container mt-4"> <!-- 遍历所有分类分组 --> {% for category, stocks in grouped_stocks.items %} {% if category %} <!-- 分类标题 --> <h3 class="mt-5">{{ category }}</h3> <!-- 分类对应的库存表格 --> <div class="table-responsive m-b-40"> <table class="table table-borderless table-data3"> <thead> <tr class="bg-primary"> <th>序号</th> <th>零件编号</th> <th>描述</th> <th>分类</th> <th>单位</th> <th>期初余额</th> <th>入库量</th> <th>总库存</th> <th>出库量</th> <th>卡账余额</th> <th>单价</th> <th>总价</th> <th>操作</th> </tr> </thead> <tbody> {% for stock in stocks %} {% if stock.obsolete %} <tr> <td>{{ forloop.counter }}</td> <td class="text-success"><i>{{ stock.part_No }}</i></td> <td class="text-success"><i>{{ stock.item_name }}(已淘汰)</i></td> <td class="text-success"><i>{{ stock.category }}</i></td> <td class="text-success"><i>{{ stock.unit }}</i></td> <td class="text-success"><i>{{ stock.balance_bd }}</i></td> <td class="text-success"><i>{{ stock.received }}</i></td> <td class="text-success"><i>{{ stock.total_bal }}</i></td> <td class="text-success"><i>{{ stock.issued }}</i></td> <td class="text-success"><i>{{ stock.tally_card_bal }}</i></td> <td class="text-success"><i>${{ stock.unit_price }}</i></td> <td class="text-success"><i>${{ stock.total_price }}</i></td> <td> <div class="table-data-feature"> <a href="{% url 'update-item' stock.id %}"> <button class="item" data-toggle="tooltip" data-placement="top" title="更新"> <i class="zmdi zmdi-edit"></i> </button> </a> <button class="item" data-toggle="tooltip" data-placement="top" title="删除"> <i class="zmdi zmdi-delete"></i> </button> </div> </td> </tr> {% else %} <tr> <td>{{ forloop.counter }}</td> <td>{{ stock.part_No }}</td> <td>{{ stock.item_name }}</td> <td>{{ stock.category }}</td> <td>{{ stock.unit }}</td> <td>{{ stock.balance_bd }}</td> <td>{{ stock.received }}</td> <td>{{ stock.total_bal }}</td> <td>{{ stock.issued }}</td> <td>{{ stock.tally_card_bal }}</td> <td>${{ stock.unit_price }}</td> <td>${{ stock.total_price }}</td> <td> <div class="table-data-feature"> <a href="{% url 'update-item' stock.id %}"> <button class="item" data-toggle="tooltip" data-placement="top" title="更新"> <i class="zmdi zmdi-edit"></i> </button> </a> <button class="item" data-toggle="tooltip" data-placement="top" title="删除"> <i class="zmdi zmdi-delete"></i> </button> </div> </td> </tr> {% endif %} {% empty %} <tr> <td colspan="13" class="text-center">该分类下无库存项</td> </tr> {% endfor %} </tbody> </table> </div> {% endif %} {% empty %} <p class="text-center">库存中无任何项</p> {% endfor %} <!-- 总价格汇总 --> <div class="text-right mt-4"> <p style="font-weight: bold; font-size: 1.2rem;">总价格: ${{ sumTotalPrice }}</p> </div> </div>
关键改动说明
视图层:
- 对查询集按
category排序,保证groupby能正确分组 - 通过
annotate计算模板所需的衍生字段,避免在模板中做复杂计算 - 将库存项按分类分组后传入模板,简化模板遍历逻辑
- 对查询集按
模板层:
- 遍历分组后的字典,每个分类生成独立标题和表格
- 保留原有库存项的样式逻辑(已淘汰项的斜体和绿色文本)
- 处理空分类、分类无库存、整体无库存的边界情况
- 总价格汇总移至所有表格下方,更符合展示逻辑
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

