Django中基于CreateView实现健身课程满员时隐藏预订表单
解决Django健身课程满员时隐藏预订表单的问题
需求说明
基于Django开发的健身项目,使用booking_create(CreateView)创建健身课程预订记录,当目标课程已被预订满时,隐藏预订表单并显示警告信息。
解决方案步骤
1. 修正模型字段(避免关键字冲突)
原模型中class是Python关键字,需重命名,同时确保Class模型包含课程容量字段:
# models.py from django.db import models from django.contrib.auth.models import User # 课程模型(补充容量字段) class Class(models.Model): name = models.CharField(max_length=100) class_capacity = models.IntegerField(default=10) # 课程最大容纳人数 # 其他课程相关字段(如时间、地点等) def __str__(self): return self.name # 预订记录模型 class Class_Book(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) class_obj = models.ForeignKey(Class, on_delete=models.CASCADE) # 重命名class为class_obj,避免关键字冲突 # 其他预订相关字段 def __str__(self): return f'{self.class_obj}'
2. 修改视图类,传递剩余名额到模板并添加提交校验
在booking_create视图中重写get_context_data方法计算剩余名额,同时在表单提交时再次校验,防止并发超订:
# views.py from django.views.generic.edit import CreateView from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from .models import Class_Book, Class from .forms import Booking_Form class booking_create(LoginRequiredMixin, CreateView): form_class = Booking_Form template_name = 'booking_create.html' success_url = reverse_lazy('home') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 从URL参数获取当前课程ID(假设URL配置为 /booking/create/<int:pk>/) class_id = self.kwargs.get('pk') current_class = Class.objects.get(pk=class_id) # 统计已预订人数 booked_count = Class_Book.objects.filter(class_obj=current_class).count() # 计算剩余名额并传入模板 context['remaining_places'] = current_class.class_capacity - booked_count context['current_course'] = current_class return context # 提交表单时再次校验,避免并发导致超订 def form_valid(self, form): class_id = self.kwargs.get('pk') current_class = Class.objects.get(pk=class_id) booked_count = Class_Book.objects.filter(class_obj=current_class).count() if current_class.class_capacity - booked_count <= 0: form.add_error(None, "该课程已预订满,无法提交预订") return self.form_invalid(form) # 关联当前用户到预订记录(如果表单未自动处理) form.instance.user = self.request.user return super().form_valid(form)
3. 修改模板,根据剩余名额显示内容
在模板中根据remaining_places的值判断显示表单还是警告信息:
<!-- booking_create.html --> {% if remaining_places > 0 %} <div class="alert alert-info"> 当前课程:{{ current_course.name }},剩余名额:{{ remaining_places }} </div> <form method="POST" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button class="btn btn-success" type="submit">确认预订</button> </form> {% else %} <div class="alert alert-danger"> 抱歉,{{ current_course.name }}课程已全部预订满,无法继续报名! </div> {% endif %} <!-- 显示表单错误信息(包括提交时的满员校验错误) --> {% if form.errors %} {% for error in form.non_field_errors %} <div class="alert alert-danger mt-3">{{ error }}</div> {% endfor %} {% endif %}
注意事项
- 确保URL配置传递课程ID,例如:
path('booking/create/<int:pk>/', booking_create.as_view(), name='booking_create') - 如果你的
Booking_Form已经自动关联用户和课程,可调整视图中的逻辑,避免重复赋值 - 高并发场景下,建议使用数据库事务或F表达式进一步优化,防止超订
内容的提问来源于stack exchange,提问作者maria
相关产品推荐
相关产品推荐

