Django CD预订系统报错:'WSGIRequest' object has no attribute 'objects'
我来帮你一步步解决这些问题,看起来你在视图函数参数、ORM查询语法和URL参数匹配上都踩了坑,咱们逐个修复:
问题1:视图函数参数错误
Django的视图函数必须以request作为第一个参数,你之前把模型类CD作为参数传入是错误的——这个参数会被Django当成URL传递的参数,而不是你导入的模型类。从报错信息TypeError: book_cd() missing 1 required positional argument: 'CD'就能看出来,Django把请求对象传给了第一个参数CD,而第二个参数cd_name没拿到值。
问题2:ORM过滤语法错误
你写的CD.objects.filter(CD.info.name == name)是完全错误的Django ORM用法:
- 不能在
filter()里写Python的比较表达式,要使用Django的双下划线关联查询语法 - 因为
CD和CDInfo是一对一关联,且设置了related_name='info',所以要通过info__name来关联查询CDInfo的name字段
问题3:模型字段的小bug
你的CDBooking模型里,when_booked = models.DateTimeField(timezone.now())这行有问题:直接调用timezone.now()会在模型加载时就固定一个时间,而不是每次创建预订记录时获取当前时间。应该改成default=timezone.now(不要加括号)。
问题4:URL参数类型不匹配
你在URL里用了<int:cd_name>,但请求的URL是book/013——带前导零的数字不是有效的整数,Django会无法匹配这个URL。如果你的cd_name是字符串类型的ID,应该改成<str:cd_name>。
修正后的完整代码
1. models.py
from django.db import models from django.utils import timezone class CD(models.Model): pass class CDInfo(models.Model): cd = models.OneToOneField(CD, on_delete=models.CASCADE, primary_key=True, related_name='info') name = models.CharField(max_length=200) class CDBooking(models.Model): cd = models.OneToOneField(CD, on_delete=models.CASCADE, primary_key=True, related_name='booking') user = models.CharField(max_length=50) when_booked = models.DateTimeField(default=timezone.now) # 修正default的写法
2. views.py(仅修正book_cd函数)
from .models import CD, CDBooking # 确保导入CDBooking def book_cd(request, cd_name): # 用双下划线查询关联的CDInfo的name字段 cd_list = CD.objects.filter(info__name=cd_name) # 遍历的时候不要用CD作为变量名,避免和模型类重名 for cd_obj in cd_list: # 确保CD已经有对应的CDBooking记录,如果没有先创建 if hasattr(cd_obj, 'booking'): cd_obj.booking.user = "test" cd_obj.booking.save() # 要保存的是booking对象,不是CD对象! else: # 如果没有预订记录,创建新的 CDBooking.objects.create(cd=cd_obj, user="test") return redirect('index')
注意:原来的代码里你写了
CD.save(),但你修改的是CD.booking.user,所以应该保存booking对象而不是CD对象,否则修改不会生效。
3. urls.py
from django.urls import path from . import views app_name = "HORSeWebSite" urlpatterns = [ path('', views.index, name='index'), # 把<int:cd_name>改成<str:cd_name>,适配带前导零的ID path('book/<str:cd_name>', views.book_cd, name='book_cd'), # name改成book_cd更合理,避免混淆 ]
额外建议
- 最好给
CD模型加一些字段,比如主键如果是自定义的字符串ID,要显式设置primary_key=True,避免默认的自增ID带来的混淆 - 处理找不到对应CD的情况:比如如果
cd_list是空的,可以返回一个提示页面,而直接跳转到首页会让用户不知道操作是否成功
内容的提问来源于stack exchange,提问作者cninja_

