I don't understand, why is my model clean
method called before full form validation.
I have required fields in my form. If I don't fill them, I don't get form errors, instead of, the model clean method is called (so I suppose it's because save
is called).
It crashes in models clean()
method:
if self.date_from > self.date_to
can't compare datetime.date to NoneType
Because I didn't filled date_to
field. I think that form should have handle it and raise ValidationError
and models save()
shouldn't be even called.
Create view should inherit form_invalid
method.
class TripCreationForm(forms.ModelForm):
date_from = forms.DateField(required=True)
date_to = forms.DateField(required=True)
place_id = forms.CharField(widget=forms.HiddenInput(),required=True)
class Meta:
model = Trip
fields = ['date_from','date_to','detail','participants','place_id']
def __init__(self, *args,**kwargs):
user = kwargs.pop('user')
super(TripCreationForm, self).__init__(*args,**kwargs)
fs_helpers.add_widget_attribute('class','datepicker',self.fields['date_from'])
fs_helpers.add_widget_attribute('class','datepicker',self.fields['date_to'])
self.instance.user = user
def clean(self):
cleaned_data = super(TripCreationForm,self).clean()
city, created = City.objects.get_or_create(place_id=self.cleaned_data['place_id'])
self.instance.city = city
date_from = self.cleaned_data.get('date_from')
date_to = self.cleaned_data.get('date_to')
if date_from and date_to and date_from>=date_to:
raise ValidationError(_('Date from can\'t be higher that date to'))
return cleaned_data
This is my view:
class TripCreationView(SuccessMessageMixin,CreateView):
form_class = TripCreationForm
template_name = 'trips/add_new_trip.html'
success_message = _('Congratulations! You\'ve added a new trip!')
context_object_name = 'trip_creation_form'
def post(self, request, *args, **kwargs): # TODO Switch to get_success_url
return super(TripCreationView, self).post(self, request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super(TripCreationView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_context_data(self, **kwargs):
context= super(TripCreationView,self).get_context_data(**kwargs)
context['trip_creation_form'] = context['form']
return context
def get_success_url(self):
return self.request.POST.get('success_url') or reverse('frontend:homepage'
)
And this is part of the model:
def save(self, *args, **kwargs):
created = not (bool(self.pk))
self.full_clean()
with transaction.atomic():
Trip.objects.stretch_trips(self)
super(Trip, self).save(*args, **kwargs)
def clean(self):
if self.date_from > self.date_to: # HERE IT CRASHES
raise ValidationError(_("Date to can't be lower than date from"))
Where is the problem? Why there is no form clean error raised?
When a model form is validated, it runs the
clean
method for the model. If you look at the full traceback, which you haven't included, then I think you'll see that the error occurs when the view callsform.is_valid()
, not when the form is saved.In your model's clean method, you should check that
self.date_from
andself.date_to
are set, similar to your form's clean method.You could remove the check from the form's
clean
method, to prevent duplication.