Django: form_valid и проверка модели - PullRequest
0 голосов
/ 17 мая 2019

Я создаю заявку на бронирование автомобиля в Джанго. Пользователи могут создать бронирование для данного автомобиля. Это происходит в /reservation/<car_id>/add. Эта форма не содержит поле Car, потому что идентификатор указан в URL. Теперь я хочу добавить проверку в модель резервирования, чтобы никакие резервирования не могли перекрываться. У меня есть следующий код (минимальная версия):

# models.py

class Car(models.Model):
    name = models.CharField(max_length=200)


class Reservation(models.Model):
    car = models.ForeignKey(Car, on_delete=models.CASCADE)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()

    def clean(self):
        # Check if overlaps with other reservations in self.car.reservation_set

# views.py

class ReservationAdd(LoginRequiredMixin, CreateView):
    template_name = 'reservation/reservation_add.html'
    model = Reservation
    form_class = ReservationAddForm

    def form_valid(self, form):
        form.instance.car = Car.objects.get(pk=self.kwargs['car_id'])
        form.instance.owner = self.request.user
        return super().form_valid(form)

# forms.py

class ReservationAddForm(forms.ModelForm):

    class Meta:
        fields = ('start_time', 'end_time')
        model = Reservation

Теперь я получаю следующую ошибку при методе Reservation.clean:

reservation.models.Reservation.car.RelatedObjectDoesNotExist: Reservation has no car.

Мне кажется, что метод clean вызывается до метода form_valid. Так что мой дизайн не совсем правильный, я думаю. Как правильно это сделать?

Ответы [ 2 ]

3 голосов
/ 17 мая 2019

Да. form_valid означает «код, запускаемый после подтверждения правильности формы».

Вам нужно внести пару изменений. Во-первых, переместите проверку в сам ReservationAddForm; и во-вторых, передайте экземпляр автомобиля в эту форму. Итак:

class ReservationAddForm(forms.ModelForm):

    class Meta:
        fields = ('start_time', 'end_time')
        model = Reservation

    def __init__(self, *args, **kwargs):
        self.car = kwargs.pop('car')
        super().__init__(*args, **kwargs)

    def clean(self):
        ... do something with self.car

class ReservationAdd(LoginRequiredMixin, CreateView):
    template_name = 'reservation/reservation_add.html'
    model = Reservation
    form_class = ReservationAddForm

    def get_form_kwargs(self):
        self.car = Car.objects.get(pk=self.kwargs['car_id'])
        kwargs = super().get_form_kwargs()
        kwargs['car'] = self.car
        return kwargs

    def form_valid(self, form):
        form.instance.car = self.car
        form.instance.owner = self.request.user
        return super().form_valid(form)
1 голос
/ 17 мая 2019

Я думаю, что лучший подход

class ReservationAdd(LoginRequiredMixin, CreateView):

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["car"] = Car.objects.get(pk=self.kwargs['car_id'])
        return kwargs

и форма модели переопределяет метод __init__

class ReservationAddForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.car = kwargs.pop("car")
        super().__init__(*args, **kwargs)

   def clean(self):
       # cleaned data
       cleaned_data = super().cleaned_data()
       # access the car instance using self.car
       # to do validation

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