Checking Two Fields
Part of the Forms section of Coddy's Django journey. Lesson 11 of 20.
The Winter Book Fair lasts three days, and an end must not come before its start. A clean_<field> method sees one field, so a rule across fields goes in clean(), which runs after every field's own checks. A booking form where a group over 6 must leave a phone number:
def clean(self):
cleaned_data = super().clean()
guests = cleaned_data.get("guests")
phone = cleaned_data.get("phone")
if guests and guests > 6 and not phone:
raise forms.ValidationError("Groups over 6 need a phone number.")
return cleaned_dataA field that failed is missing from cleaned_data, and an empty optional date is None, so read with .get() and compare only when both values are there.
An error raised in clean() belongs to the whole form, so the field loop does not draw it. {{ form.non_field_errors }} does.
Challenge
MediumEvents get an end date.
- In
events/forms.py, add an optionalend_datedate field toEventForm. Writeclean(): when both dates are there and the end comes first, raiseThe event cannot end before it starts.Read the dates with.get(). - In
new_event, saveend_datetoo. - In
new_event.html, drawform.non_field_errorsabove the loop.
Set the end before the start: you see that message.
Try it yourself
import datetime
from django import forms
class EventForm(forms.Form):
title = forms.CharField(max_length=100)
date = forms.DateField()
place = forms.CharField(max_length=100)
description = forms.CharField(widget=forms.Textarea, required=False)
capacity = forms.IntegerField(min_value=1)
def clean_date(self):
date = self.cleaned_data["date"]
if date < datetime.date.today():
raise forms.ValidationError("The date cannot be in the past.")
return date
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Forms
2Django Forms
A Django FormDrawing a FormPractice on your own: Django playground