如何在Django ModelForm中拆分日期与时段选择字段
解决方案
1. 修改ModelForm,新增日期选择字段
我们需要在表单中添加一个额外的selected_date字段用于选择可用日期,同时调整booked_time字段的初始状态,实现先选日期再加载对应时段的逻辑:
from django import forms from .models import Bookings, AvailableDates, AvailableHours class BookingForm2(forms.ModelForm): # 新增日期选择字段,仅展示可用状态的日期 selected_date = forms.ModelChoiceField( queryset=AvailableDates.objects.filter(status=True), label="انتخاب تاریخ", required=True ) class Meta: model = Bookings exclude = ('user','booking_code','confirmed',) widgets = { # 初始隐藏并禁用时段选择框,选完日期后再启用 'booked_time': forms.Select(attrs={'disabled': 'disabled', 'style': 'display:none;'}), } def __init__(self,*args, **kwargs): super(BookingForm2, self).__init__(*args, **kwargs) # 初始时段列表为空 self.fields['booked_time'].queryset = AvailableHours.objects.none() # 处理表单提交时的日期参数,加载对应时段 if 'selected_date' in self.data: try: date_id = int(self.data.get('selected_date')) self.fields['booked_time'].queryset = AvailableHours.objects.filter( free_date_id=date_id, status=True ) except (ValueError, TypeError): pass # 编辑已有预约时,自动填充日期和对应时段 elif self.instance.pk: self.fields['selected_date'].initial = self.instance.booked_time.free_date self.fields['booked_time'].queryset = AvailableHours.objects.filter( free_date=self.instance.booked_time.free_date, status=True )
2. 编写AJAX视图,动态加载时段
创建视图函数接收日期ID,返回该日期下的可用时段数据:
from django.http import JsonResponse from .models import AvailableHours def load_hours(request): date_id = request.GET.get('date_id') hours = AvailableHours.objects.filter(free_date_id=date_id, status=True).values('id', 'free_hours_from', 'free_hours_to') # 构造前端需要的选项格式 hour_options = [{'id': hour['id'], 'text': f"{hour['free_hours_from']} الی {hour['free_hours_to']}"} for hour in hours] return JsonResponse(hour_options, safe=False)
在urls.py中添加对应路由:
from django.urls import path from . import views urlpatterns = [ # 其他路由... path('load-hours/', views.load_hours, name='load_hours'), ]
3. 前端模板实现联动逻辑
通过JavaScript监听日期选择事件,发送AJAX请求更新时段选项:
<form method="post"> {% csrf_token %} {{ form.selected_date.label_tag }} {{ form.selected_date }} <br> {{ form.booker_name.label_tag }} {{ form.booker_name }} <br> {{ form.booked_time.label_tag }} {{ form.booked_time }} <button type="submit">ثبت رزرو</button> </form> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { // 监听日期选择变化 $('#id_selected_date').change(function() { var dateId = $(this).val(); if (dateId) { $.ajax({ url: '{% url "load_hours" %}', data: {'date_id': dateId}, dataType: 'json', success: function(data) { $('#id_booked_time').empty(); // 填充时段选项 $.each(data, function(index, hour) { $('#id_booked_time').append($('<option>', { value: hour.id, text: hour.text })); }); // 启用并显示时段选择框 $('#id_booked_time').prop('disabled', false).show(); } }); } else { // 未选日期时清空并隐藏时段框 $('#id_booked_time').empty().prop('disabled', true).hide(); } }); // 页面加载时,若已有选中日期则自动触发加载 if ($('#id_selected_date').val()) { $('#id_selected_date').trigger('change'); } }); </script>
4. 表单验证增强
添加验证确保用户必须选择有效时段:
class BookingForm2(forms.ModelForm): # 前面的代码... def clean(self): cleaned_data = super().clean() booked_time = cleaned_data.get('booked_time') if not booked_time: raise forms.ValidationError("لطفاً یک سانس انتخاب کنید.") return cleaned_data
内容的提问来源于stack exchange,提问作者Essiprog
相关产品推荐
相关产品推荐

