from django import forms
from .models import Event
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['title', 'description', 'start_date', 'end_date', 'capacity']
def clean_capacity(self):
capacity = self.cleaned_data.get('capacity')
if capacity and capacity < 1:
raise forms.ValidationError('Capacity must be at least 1')
return capacity
def clean(self):
cleaned_data = super().clean()
start_date = cleaned_data.get('start_date')
end_date = cleaned_data.get('end_date')
if start_date and end_date:
if end_date <= start_date:
self.add_error(
'end_date',
'End date must be after start date'
)
return cleaned_data
I use clean_<fieldname>() to validate individual fields and clean() to validate field combinations. Raising ValidationError shows the message to the user near the appropriate field. For cross-field validation (like 'end date must be after start date'), I override clean() and attach errors with add_error(). I keep validation logic in forms rather than models because it's often context-dependent. Using cleaned_data ensures I'm working with validated, type-converted values. This pattern keeps forms self-contained and easy to test.