如何移除已选时段避免重复预订(Django理发预约系统)
解决理发师预订时段重复选择问题
要实现「特定日期下,理发师已被预订的时段从列表中移除」的需求,我们需要从表单动态过滤选项、提交时并发验证、前端实时更新三个层面入手,以下是具体实现方案:
1. 修改表单逻辑,动态生成可选时段
在forms.py中,让表单根据用户选择的日期和理发师自动过滤已预订时段,同时在提交时二次验证防止并发冲突:
from .models import Booking, TIME_SLOTS import datetime from django import forms class DatePicker(forms.DateInput): input_type = 'date' class BookingForm(forms.ModelForm): class Meta: model = Booking fields = ('date', 'time', 'barber', 'service',) widgets = { 'date': DatePicker(), } def __init__(self, *args, **kwargs): # 从参数中获取用户已选的日期和理发师(可选) self.selected_date = kwargs.pop('selected_date', None) self.selected_barber = kwargs.pop('selected_barber', None) super().__init__(*args, **kwargs) # 若有明确的日期和理发师,过滤已预订时段 if self.selected_date and self.selected_barber: # 查询该日期该理发师已被占用的时段 booked_times = Booking.objects.filter( date=self.selected_date, barber=self.selected_barber ).values_list('time', flat=True) # 从预设时段中剔除已占用的选项 available_times = [slot for slot in TIME_SLOTS if slot[0] not in booked_times] self.fields['time'].choices = available_times else: # 默认显示所有时段 self.fields['time'].choices = TIME_SLOTS def clean(self): cleaned_data = super().clean() date = cleaned_data.get('date') time = cleaned_data.get('time') barber = cleaned_data.get('barber') # 提交时二次验证,避免多用户并发预订同一时段 if date and time and barber: if Booking.objects.filter(date=date, time=time, barber=barber).exists(): raise forms.ValidationError(f"时段{time}已被预订,请选择其他时段。") return cleaned_data
2. 更新视图,支持动态参数传递
修改views.py,让视图接收日期和理发师的查询参数,初始化表单时传入这些参数,确保表单显示正确的可选时段:
from django.shortcuts import render from django.contrib.auth.decorators import login_required from django.contrib import messages from django.http import HttpResponseRedirect from .models import Booking from .forms import BookingForm from datetime import date @login_required() def make_booking(request): selected_date = request.GET.get('date') selected_barber = request.GET.get('barber') # 将前端传来的日期字符串转换为date对象 if selected_date: try: selected_date = date.fromisoformat(selected_date) except ValueError: selected_date = None if request.method == "POST": # 提交时传入选中的日期和理发师,确保表单验证时能正确过滤 form = BookingForm( request.POST, selected_date=request.POST.get('date'), selected_barber=request.POST.get('barber') ) if form.is_valid(): booking_form = form.save(commit=False) booking_form.customer = request.user booking_form.save() messages.success(request, '您的预订已提交,等待确认') return HttpResponseRedirect('/bookings') else: # GET请求时,根据查询参数初始化表单 form = BookingForm( selected_date=selected_date, selected_barber=selected_barber ) return render(request, 'bookings.html', {'form': form})
3. 前端实时更新(可选,提升用户体验)
在bookings.html中添加AJAX逻辑,当用户选择日期或理发师后,自动更新时段下拉框,无需刷新页面:
<form method="post" id="booking-form"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交预订</button> </form> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { // 监听日期和理发师选择框的变化事件 $('#id_date, #id_barber').change(function() { var date = $('#id_date').val(); var barber = $('#id_barber').val(); // 发送GET请求获取更新后的表单片段 $.get('{% url "make_booking" %}', {date: date, barber: barber}, function(data) { // 替换时段下拉框的选项 var new_time_options = $(data).find('#id_time').html(); $('#id_time').html(new_time_options); }); }); }); </script>
4. 补充URL配置
确保在urls.py中给视图命名,让前端的{% url %}标签能正确生成请求地址:
from django.urls import path from . import views urlpatterns = [ path('book/', views.make_booking, name='make_booking'), # 其他URL配置... ]
关键逻辑说明
- 动态过滤时段:表单初始化时根据已选日期和理发师,从数据库查询已预订时段,剔除后生成可选列表
- 并发验证:提交时再次检查时段是否被占用,避免多个用户同时提交同一时段导致的重复预订
- 实时更新:通过AJAX实现无刷新更新时段列表,提升用户操作体验
内容的提问来源于stack exchange,提问作者AriRix1410
相关产品推荐
相关产品推荐

