首页 > 解决方案 > 如何在 Django Form 中将 2 个日期时间字段分解为 1 个日期和 2 个时间?

问题描述

好的,所以我正在尝试预订时段(如活动/预订)。

#models.py
class BookingSlot(models.Model):
    start_time = models.DateTimeField("Start Time")
    end_time = models.DateTimeField("End Time")
    location = models.ForeignKey(Court, on_delete=models.CASCADE)

如您所见,该模型有 2 个日期时间字段。我想制作一个用于创建预订空档的表格,该表格只包含一个日期和两次(假设它是同一天)。我知道我可以改变我的模型,但这会产生一些问题。

#forms.py
class BookingSlotForm(ModelForm):
    class Meta:
        model = BookingSlot
        fields = ['start_time', 'end_time', 'location']

我想知道是否有一种方法可以编辑我的 forms.py 来做到这一点。看起来这很简单,我只是不确定如何为它制定一个问题。

#views.py
class CreateBookingForm(CreateView):
    template_name = 'app_book/create_bookings.html'
    form_class = BookingSlotForm
    success_message = 'Booking slot created'

标签: djangodjango-forms

解决方案


为此,您需要:

  1. DateTimeField在您的模型表单中不包含模型
  2. 相反,包括一个表单DateField和两个TimeFields
  3. DateTimeField保存时,通过组合表单字段来填充新实例

所以是这样的:

class BookingSlotForm(ModelForm):
    class Meta:
        model = BookingSlot
        fields = ['location']

    slot_date = forms.DateField()
    start_time = forms.TimeField()
    end_time = forms.TimeField()

    def save(self, commit=True):
        slot = super(BookingSlotForm, self).save(commit=False)
        slot.start_time = datetime.combine(self.cleaned_data['slot_date'], self.cleaned_data['start_time'])
        slot.end_time = datetime.combine(self.cleaned_data['slot_date'], self.cleand_data['end_time'])
        if commit:
            slot.save()
        return slot

如果您的表单有 m2m 字段,您还需要save_m2m()在保存实例后调用该方法 when commit=True。而且我忽略了结束时间在开始时间之后的验证 - 这是您clean()在模型表单上使用自定义方法所做的事情,因为它需要比较两个字段的值。

如果您想使用这样的东西进行编辑,您还需要覆盖表单类的__init__方法以从实例中复制正确的值(如果有)。看起来像这样:

def __init__(self, *args, **kwargs):
    instance = kwargs.get('instance')
    if instance:
        initial = kwargs.get('initial', {})
        # Here I'm not considering the possibility of the slot having different dates
        initial['slot_date'] = instance.start_time.date()
        initial['start_time'] = instance.start_time.time()
        initial['end_time'] = instance.end_time.time()
        kwargs['initial'] = initial
    super(BookingSlotForm, self).__init__(*args, **kwargs)

推荐阅读