Django获取ForeignKey ID时出现TypeError无法解包非可迭代对象问题
问题原因
你代码里invoice视图函数的这一行写法错误:
cust_id = Invoice.objects.get(id, customers=customer.id)
Django的ORM get()方法要求所有筛选条件都以关键字参数形式传入,你这里直接写id是把Python内置的id()函数作为位置参数传给了get(),get()方法无法解析这个函数对象,所以抛出了TypeError: cannot unpack non-iterable builtin_function_or_method object错误。
而且你这里完全不需要再查询一次数据库:调用Invoice.objects.create()的时候会直接返回刚创建的Invoice实例,直接复用即可。
修复方案
1. 修复当前报错
把视图里创建发票后的查询代码删掉,直接复用create返回的实例:
# 原来的创建代码保留 new_invoice = Invoice.objects.create( products = product, quantity = qt, total=total, customers = customer ) # 删掉原来的 Invoice.objects.get 那一行,直接用new_invoice取值 product_name = new_invoice.products product_quantity = new_invoice.quantity product_total = new_invoice.total
2. 调整模型满足「同一张发票添加多个产品」的需求
你现在的模型设计有问题:Invoice和Product用ForeignKey关联,意味着一张发票只能对应一个产品,不符合你的需求。需要新增中间表InvoiceItem存储发票下的每个商品条目:
修正后的models.py
from django.db import models from account.models import Customer from product.models import Product # 发票主表:一张发票对应一个客户,包含多个商品 class Invoice(models.Model): customer = models.ForeignKey(Customer, on_delete=models.CASCADE, verbose_name="所属客户") date = models.DateTimeField(auto_now_add=True, verbose_name="开票日期") total_amount = models.BigIntegerField(default=0, verbose_name="发票总金额") class Meta: verbose_name = "发票" verbose_name_plural = verbose_name # 发票商品条目:关联发票和商品,存储单个商品的购买信息 class InvoiceItem(models.Model): invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name="items", verbose_name="所属发票") product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name="商品") quantity = models.IntegerField(default=1, verbose_name="购买数量") item_total = models.BigIntegerField(default=0, verbose_name="该商品总金额") class Meta: verbose_name = "发票商品条目" verbose_name_plural = verbose_name
3. 实现「按客户ID筛选所有发票」的需求
模型调整后,只需要用ORM的filter方法即可查询指定客户的所有发票:
# 示例:查询客户id为1的所有发票 customer_invoices = Invoice.objects.filter(customer_id=1) # 还可以预加载发票下的所有商品,减少查询次数 customer_invoices = Invoice.objects.filter(customer_id=1).prefetch_related("items")
4. 其他优化建议
- 字段命名尽量见名知意,
customers改为customer(一张发票只对应一个客户,用单数更合理) - 用
get_object_or_404替代直接get(),避免查询不到对象时抛出500错误 - 操作session前先判断
customerId是否存在,避免未走billingform直接访问invoice视图时报错
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

