创建Receipt后跳转RentPayment表单时出现TypeError问题求助
问题与解决方案:创建Receipt后跳转RentPayment表单的TypeError修复
问题描述
我有两个模型Receipt和RentPayment,需求是创建Receipt后,跳转到RentPayment表单并将receipt字段的初始值设为刚保存的Receipt。但当前访问/accounts/add_rent_payment/1363902a-c341-4883-84ee-1e12156b0381时出现TypeError。
相关代码
models.py
class Receipt(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) receipt_number = models.CharField(max_length=4, null=True, blank=True) property = models.ForeignKey(Property, null=False, blank=False, on_delete=models.CASCADE) month_paid = models.CharField(max_length=15,null=True,blank=True,choices=MONTHS) balance_due = models.DecimalField(max_digits=5, decimal_places=2) total_rent = models.DecimalField(max_digits=7, decimal_places=2, null=True,blank=True) class RentPayment(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) receipt = models.ForeignKey(Receipt, null=True, blank=True, on_delete=models.CASCADE) property = models.ForeignKey(Property, null=True, blank=True, on_delete=models.SET_NULL) amount_paid = models.DecimalField(max_digits=7, decimal_places=2) payment_date = models.DateField(auto_now=True) next_payment_due = models.DateField(auto_now=True)
views.py
def createReceipt(request,pk): property_entity = Property.objects.get(id=pk) form = ReceiptForm(initial={'property' :property_entity}) if request.method == 'POST': form = ReceiptForm(request.POST, initial={'property' :property_entity}) if form.is_valid(): receipt_obj = form.save(commit=False) receipt_obj.property = property_entity receipt_obj.save() return redirect('add_rent_payment', receipt_pk=receipt_obj.id) else: ReceiptForm() context = {'property_entity' :property_entity, 'form' :form } return render(request,"accounting/receipt.html",context) def add_rent_payment(request, pk): receipt = Receipt.objects.get(id=pk) if request.method == 'POST': rent_payment_form = RentPaymentForm(request.POST) if rent_payment_form.is_valid(): rent_payment = rent_payment_form.save(commit=False) rent_payment.receipt = receipt rent_payment.save() return redirect('property_list') else: rent_payment_form = RentPaymentForm() context = { 'receipt': receipt, 'rent_payment_form': rent_payment_form, } return render(request, 'accounting/add_rent_payment.html', context)
urls.py
urlpatterns = [ path('receipt/<str:pk>', views.createReceipt, name="receipt"), path('add_rent_payment/<str:receipt_pk>', views.add_rent_payment, name="add_rent_payment") ]
错误原因
- URL与视图参数不匹配:urls.py中
add_rent_payment的路径参数是<str:receipt_pk>,但视图函数add_rent_payment接收的参数是pk,参数名不一致触发TypeError。 - 表单未设置初始值:RentPayment表单未传入receipt的初始值,无法实现需求中的默认填充。
- createReceipt视图分支无效:else分支仅实例化ReceiptForm但未赋值给form变量,可能引发异常。
修复步骤
1. 统一URL与视图的参数名
两种修正方式二选一:
- 方式一:修改urls.py的参数名,与视图保持一致
urlpatterns = [ path('receipt/<str:pk>', views.createReceipt, name="receipt"), path('add_rent_payment/<str:pk>', views.add_rent_payment, name="add_rent_payment") ]
- 方式二:修改视图函数的参数名,与URL保持一致
def add_rent_payment(request, receipt_pk): receipt = Receipt.objects.get(id=receipt_pk) # 后续代码不变
同时修改createReceipt中的跳转参数,与URL定义匹配:
# 如果用方式一,跳转参数改为pk return redirect('add_rent_payment', pk=receipt_obj.id) # 如果用方式二,保持receipt_pk不变 return redirect('add_rent_payment', receipt_pk=receipt_obj.id)
2. 给RentPaymentForm设置初始值
修改add_rent_payment视图的GET分支,传入initial参数填充receipt和关联的property:
def add_rent_payment(request, pk): receipt = Receipt.objects.get(id=pk) if request.method == 'POST': rent_payment_form = RentPaymentForm(request.POST) if rent_payment_form.is_valid(): rent_payment = rent_payment_form.save(commit=False) rent_payment.receipt = receipt rent_payment.property = receipt.property # 同步property字段,避免重复选择 rent_payment.save() return redirect('property_list') else: # 设置表单初始值 rent_payment_form = RentPaymentForm(initial={'receipt': receipt, 'property': receipt.property}) context = { 'receipt': receipt, 'rent_payment_form': rent_payment_form, } return render(request, 'accounting/add_rent_payment.html', context)
3. 修复createReceipt视图的else分支
修正else分支的无效代码,确保form变量正确赋值:
def createReceipt(request,pk): property_entity = Property.objects.get(id=pk) if request.method == 'POST': form = ReceiptForm(request.POST) if form.is_valid(): receipt_obj = form.save(commit=False) receipt_obj.property = property_entity receipt_obj.save() return redirect('add_rent_payment', pk=receipt_obj.id) else: form = ReceiptForm(initial={'property' :property_entity}) context = {'property_entity' :property_entity, 'form' :form } return render(request,"accounting/receipt.html",context)
可选:优化表单字段(隐藏不可编辑项)
如果希望receipt和property字段不可编辑,可在RentPaymentForm中设置隐藏组件:
from django import forms from .models import RentPayment class RentPaymentForm(forms.ModelForm): class Meta: model = RentPayment fields = ['receipt', 'property', 'amount_paid'] widgets = { 'receipt': forms.HiddenInput(), 'property': forms.HiddenInput(), }
内容的提问来源于stack exchange,提问作者Jaks
相关产品推荐
相关产品推荐

