Django预订系统编辑功能报错:__init__()收到意外参数'id'
Django预订系统编辑功能报错解决
核心错误原因
你遇到的TypeError: __init__() got an unexpected keyword argument 'id'是因为混用了类视图和函数视图:
- URL配置指向了
EditBooking类,但Django会将URL中的id参数传递给类的构造函数__init__,而你定义的__init__没有接收该参数。 - 你在类内部写了函数视图
edit_booking,这不符合Django视图规范,类视图需要继承基类并实现特定方法,而非在类中嵌套函数视图。
分步修复方案
1. 修正视图实现
方案A:改用纯函数视图(贴合你原有逻辑)
删除EditBooking类,直接保留并修正edit_booking函数:
from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.contrib import messages from .models import Booking, UserProfile from .forms import BookingForm @login_required def edit_booking(request, id): booking = get_object_or_404(Booking, id=id) # 权限校验:仅允许用户编辑自己的预订 if booking.booking_customer.user != request.user: messages.error(request, "你无权编辑此预订") return redirect('profile') template_name = 'edit_booking.html' if request.method == 'POST': form = BookingForm(request.POST, instance=booking) if form.is_valid(): instance = form.save(commit=False) # 关联当前登录用户的UserProfile(修正模型字段名错误:原代码用customer_data,模型里是booking_customer) instance.booking_customer = UserProfile.objects.get(user=request.user) instance.save() messages.success(request, '感谢!你的预订已更新!') return redirect('profile') # 保存后跳转回个人页面 else: messages.error(request, '更新失败,请检查表单错误') else: # 直接用booking实例初始化表单,无需手动编写initial form = BookingForm(instance=booking) return render(request, template_name, {'form': form, 'booking': booking})
方案B:改用类视图(符合Django规范)
如果想用类视图,继承UpdateView而非DetailView,并添加登录校验:
from django.views.generic.edit import UpdateView from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib import messages from django.urls import reverse_lazy from django.shortcuts import redirect from .models import Booking from .forms import BookingForm class EditBooking(LoginRequiredMixin, UpdateView): model = Booking form_class = BookingForm template_name = 'edit_booking.html' success_url = reverse_lazy('profile') pk_url_kwarg = 'id' # 指定URL参数名为id,保持和原有URL一致 def get_object(self, queryset=None): obj = super().get_object(queryset) # 权限校验 if obj.booking_customer.user != self.request.user: messages.error(self.request, "你无权编辑此预订") return redirect('profile') return obj def form_valid(self, form): messages.success(self.request, '感谢!你的预订已更新!') return super().form_valid(form) def form_invalid(self, form): messages.error(self.request, '更新失败,请检查表单错误') return super().form_invalid(form)
2. 修正URL配置
- 如果用函数视图,URL指向函数:
path('edit-booking/<int:id>', views.edit_booking, name='editbooking'),
- 如果用类视图,需要调用
as_view()方法:
path('edit-booking/<int:id>', views.EditBooking.as_view(), name='editbooking'),
3. 修正表单错误
表单里存在两处关键问题,需要调整:
from django import forms from django.core.exceptions import ValidationError from django.utils import timezone from crispy_forms.helper import FormHelper from crispy_forms.layout import Submit from .models import Booking, TIME_SLOTS, TABLE_SIZE from django_summernote.widgets import SummernoteWidget class BookingForm(forms.ModelForm): """ Provides necessary fields to the booking form for customers """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Crispy form helpers self.helper = FormHelper() self.helper.form_method = 'post' self.helper.add_input(Submit('submit', 'Submit', css_class='btn btn-secondary btn-brown mb-4 mx-auto px-5')) # 日期字段优化:移除默认value,让表单自动填充现有预订日期 booking_date = forms.DateField( widget=forms.DateInput(attrs={'class':'form-control', 'type':'date'}), required=True ) booking_time = forms.ChoiceField(choices=TIME_SLOTS, required=True) table_size = forms.ChoiceField(choices=TABLE_SIZE, required=True) additional_info = forms.CharField( max_length=400, widget=SummernoteWidget(), required=False ) class Meta: model = Booking fields = ['booking_date', 'booking_time', 'table_size', 'additional_info'] # booked_on是自动生成字段,无需在表单中展示 readonly_fields = [] # 日期校验:改用Django表单规范的clean_xxx方法 def clean_booking_date(self): booking_date = self.cleaned_data.get('booking_date') if booking_date < timezone.localdate(): raise ValidationError("日期不能是过去的时间!") return booking_date
- 移除了Form中重复定义的
slug字段(模型已配置AutoSlugField,无需在表单中处理) - 将日期校验逻辑改为
clean_booking_date方法,符合Django表单验证规范 - 修正了字段必填性(原代码设为
required=False,但预订日期、时间、桌型应为必填项)
4. 模板调整
确保模板中的URL参数与配置一致:
- profile.html中的编辑按钮:
<a href="{% url 'editbooking' id=booking.id %}" aria-label="edit booking"> <button type="button" class="btn btn-secondary btn-brown px-5">Edit</button> </a>
- edit_booking.html中的表单action:
<form method="POST" action="{% url 'editbooking' id=booking.id %}" class="col-6"> {% csrf_token %} {% crispy form %} </form>
内容的提问来源于stack exchange,提问作者TulaUnogi
相关产品推荐
相关产品推荐

