Django:form_valid和模型验证

时间:2019-05-17 12:46:50

标签: python django

我正在Django中创建一个汽车预订应用程序。用户可以为给定的汽车创建预订。这发生在/reservation/<car_id>/add。该表单不包含Car字段,因为ID是在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 个答案:

答案 0 :(得分:3)

是的。 form_valid的意思是“一旦确认表单有效,便要运行的代码”。

您需要进行一些更改。首先,将您的验证移至ReservationAddForm本身;其次,将Car实例传递给该形式。所以:

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 :(得分:1)

我认为更好的方法是

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