Django查询PostgreSQL返回数组数据如何拆分渲染到HTML表格
解决方案
核心问题为你当前的模型将同一张发票下的多个商品的名称、单价、数量都以字符串形式的数组字面量存在同一行字段中,且模板仅遍历发票行对象,没有拆分每个商品条目,因此会直接输出整个数组字符串。
方案一:快速兼容方案(无需修改现有表结构和存量数据)
1. 修改视图代码,解析字符串数组并配对商品
使用ast.literal_eval安全解析字符串格式的数组为Python列表,再通过zip方法将三个数组的同位置元素配对为单个商品条目:
import ast from django.shortcuts import render from .models import PurchaseInvoice def purchaseDetails(request,pk): # 取对应发票数据 invo_data = PurchaseInvoice.objects.filter(invoice=pk).first() # 解析字符串为列表 product_names = ast.literal_eval(invo_data.product_name) prices = ast.literal_eval(invo_data.price) quantities = ast.literal_eval(invo_data.quantity) # 配对生成商品列表 product_list = [ {"name": name, "price": price, "quantity": qty, "amount": float(price)*int(qty)} for name, price, qty in zip(product_names, prices, quantities) ] return render(request,'purchase/invoice_details.html',{ 'invoice': invo_data, 'product_list': product_list })
2. 修改HTML模板代码,遍历商品列表渲染表格
直接遍历生成好的商品列表,每个商品对应一行:
{% for product in product_list %} <tr> <td>{{ product.name }}</td> <td>{{ product.price }}</td> <td>{{ product.quantity }}</td> <td>{{ product.amount }}</td> </tr> {% endfor %}
方案二:规范优化方案(长期使用推荐,符合数据库设计范式)
现有表结构不符合数据库第一范式,存在多字段数组长度不匹配、无法单独查询/修改单个商品、数值计算效率低等问题,推荐拆分为发票主表和商品明细表:
1. 调整模型定义
from django.db import models from datetime import date # 发票主表,存发票公共信息 class PurchaseInvoice(models.Model): id = models.AutoField(primary_key=True) vendor = models.CharField(max_length=50) invoice = models.CharField(max_length=20) date = models.DateField(default=date.today) def __str__(self): return self.invoice # 商品明细表,存单个商品信息,和发票主表一对多关联 class PurchaseInvoiceItem(models.Model): invoice = models.ForeignKey(PurchaseInvoice, on_delete=models.CASCADE, related_name="items") product_name = models.CharField(max_length=500) # 用数值类型存价格、数量,避免字符串转义问题 price = models.DecimalField(max_digits=10, decimal_places=2) quantity = models.IntegerField() @property def amount(self): return self.price * self.quantity
调整模型后执行makemigrations和migrate同步数据库,将存量数据拆分写入明细表即可。
2. 修改视图代码
def purchaseDetails(request,pk): # 预加载关联的商品明细,避免N+1查询 invo_data = PurchaseInvoice.objects.filter(invoice=pk).prefetch_related("items").first() return render(request,'purchase/invoice_details.html',{'invoice': invo_data})
3. 修改HTML模板代码
{% for item in invoice.items.all %} <tr> <td>{{ item.product_name }}</td> <td>{{ item.price }}</td> <td>{{ item.quantity }}</td> <td>{{ item.amount }}</td> </tr> {% endfor %}
内容的提问来源于stack exchange,提问作者Shanzedul
相关产品推荐
相关产品推荐

