Использование метода модели в проверке формы - PullRequest
0 голосов
/ 10 ноября 2018

У меня есть 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 голосов
/ 10 ноября 2018

Способ best довольно субъективен, но вот способ , который не слишком сложен.

В вашей модели вызовите метод в clean. ModelForm вызовет метод очистки вашей модели во время процесса проверки (перед завершением сохранения).

Вот соответствующие части источника:

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 в форме нарушает порядок разрешения метода, поэтому чистота вашей модели не будет вызываться так, как это написано.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...