在表单验证中使用模型方法

时间:2018-11-10 01:27:29

标签: django django-models django-forms

我有一个ModelForm,并且我想使用我的Model方法进行表单验证过程,我尝试了form.save(commit=False),但是它返回了一个None对象。 期间模型具有两个属性,分别是开始时间字段和结束时间字段。

models.py

class Booking(models.Model):
    CATEGORY_CHOICES = (
        ('Web', 'Web Application'),
        ('Emb', 'Embedded Application')
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bookings')
    room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='bookings')
    category = models.CharField(max_length=50, choices=CATEGORY_CHOICES, default='Web')
    date = models.DateField('Booking Date', db_index=True)
    start = models.ForeignKey(Period, on_delete=models.SET_NULL, related_name='start_at', null=True)
    end = models.ForeignKey(Period, on_delete=models.SET_NULL, related_name='end_at', null=True)
    used = models.BooleanField(default=False)

    objects = BookingManager()

    class Meta:
        ordering = ['-date']

    def get_start_time(self):
        return datetime.datetime.combine(self.date, self.start.start,
                                         tzinfo=timezone.get_current_timezone())

    def get_end_time(self):
        return datetime.datetime.combine(self.date, self.end.end,
                                         tzinfo=timezone.get_current_timezone())

    def is_occurring(self):
        now = timezone.localtime(timezone.now())
        return (now >= self.get_start_time()) and (now <= self.get_end_time())

    def extend_booking_time(self):
        next_end = self.end.next_period()

        if next_end is None:
            raise ValidationError("Invalid extending period")

        if not next_end.is_available(self.date, next_end):
            raise ValidationError("Overlapped extension")

        else:
            self.end = next_end
            self.save()

    def check_in(self):
        # Create record
        '''
        Log.objects.create(user=self.user.username, 
            room=self.room, booking= self.id)
        '''
        self.used = True
        self.save()

    def check_out(self, time):
        # Record Log
        #log = Log.objects.get(booking=self.id)
        #log.check_out = time
        #log.save()
        self.delete()

    def check_periods(self):
        return self.start.start < self.end.end

    def check_time(self):
        now = timezone.localtime(timezone.now())
        if now >= self.get_end_time():
            return False
        else:
            return True

    def check_overlap(self):
        start = self.get_start_time()
        end = self.get_end_time()        
        bookings = Booking.objects.filter(room=self.room, date=self.date)

        for booking in bookings:
            if (start < booking.get_end_time()) and (end > booking.get_start_time()):
                return False

        return True


    def clean(self):
        if not self.check_periods():
            raise ValidationError('Period error!')

        if not self.check_time():
            raise ValidationError('Time error!')

        if not self.check_overlap():
            raise ValidationError('Overlap error!')

forms.py

class BookingForm(forms.ModelForm):
    class Meta:
        model = Booking
        fields= ['room', 'date', 'start', 'end']

    def __init__(self, *args, **kwargs):
        initial_args = kwargs.get('initial', None)
        if initial_args:
            super(BookingForm, self).__init__(*args, **kwargs)
            self.fields['start'].widget = forms.TextInput()
            self.fields['date'].widget.attrs['readonly'] = True
            self.fields['start'].widget.attrs['readonly'] = True
            self.fields['room'].queryset = Room.objects.filter(
                id=initial_args['room'].id
            )
            self.fields['end'].queryset = Period.objects.get_available_periods(
                initial_args['room'],
                initial_args['date'],
                initial_args['start']
            )

    def clean_date(self):
        now = timezone.localtime(timezone.now()).date()
        date = self.cleaned_data['date']
        if date < now:
            raise ValidationError('Ngay dang ky khong hop le')

        return date

    def clean(self):
        pass

views.py

class BookingCreateView(LoginRequiredMixin, CreateView):
    login_url = 'login'
    form_class = BookingForm
    template_name = 'booking_add.html'
    success_url = reverse_lazy('booking_list')

    def get(self, request, *args, **kwargs):
        room = self.request.GET.get('room', None)
        date = self.request.GET.get('date', None)
        start = self.request.GET.get('start', None)
        if room is None or date is None or start is None:
            return redirect('select')
        else:
            room_object = get_object_or_404(Room, id=room)
            period = get_object_or_404(Period, number=start)
            date = datetime.datetime.strptime(
                date, '%d-%m-%Y'
            ).replace(tzinfo=timezone.get_current_timezone())

            if period.is_expired(date) or not period.is_available(room, date):
                return redirect(room_object.get_absolute_url())

        return super(BookingCreateView, self).get(request, *args, **kwargs)

    def get_initial(self):
        initial = super(BookingCreateView, self).get_initial()
        initial['date'] = datetime.datetime.strptime(
            self.request.GET.get('date'), '%d-%m-%Y'
        )
        initial['room'] = get_object_or_404(
            Room, id=self.request.GET.get('room')
        )
        initial['start'] = get_object_or_404(
            Period, number=self.request.GET.get('start')
        )
        return initial

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)

模板。

<main>
    <div class="reg-form">
        <form class="form" method="post" action="">
            {% csrf_token %}
            <label for="room">Phòng</label>
            {{ form.room }}
            <label for="date">Ngày</label>
            {{ form.date }}
            <label for="start">Ca bắt đầu</label>
            {{ form.start }}
            <label for="end">Ca kết thúc</label>
            {{ form.end }}
            <button type="submit">Đăng ký</button>
            <p>{{ form.errors }}</p>
        </form>
    </div>
</main>

我想在check_overlap验证过程中使用方法BookingForm,什么是最好的方法?

1 个答案:

答案 0 :(得分:0)

最佳方法是非常主观的,但是这里的 a 方法并不太复杂。

在模型中,调用clean中的方法。在验证过程中(完成保存之前),ModelForm将调用模型的clean方法。

以下是相关的来源部分:

https://github.com/django/django/blob/master/django/forms/models.py#L381 https://github.com/django/django/blob/master/django/forms/models.py#L381

这是模型验证文档:https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects

在表单上覆盖clean会破坏方法的解析顺序,因此不会以编写代码的方式调用模型的原始代码。

希望这会有所帮助!