You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:43:43