You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建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")
]

错误原因

  1. URL与视图参数不匹配:urls.py中add_rent_payment的路径参数是<str:receipt_pk>,但视图函数add_rent_payment接收的参数是pk,参数名不一致触发TypeError。
  2. 表单未设置初始值:RentPayment表单未传入receipt的初始值,无法实现需求中的默认填充。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 00:35:40