Introduction
Sometimes validation rules depend on other field values or external conditions.
Key Concepts
Conditional Logic: Rules that depend on other fields.
Optional Requirements: Required only under certain conditions.
Real World Context
A checkout form needs address fields only for delivery, not store pickup. Conditional validation in clean() enforces these context-dependent rules.
Deep Dive
Field-Dependent Validation
pythonclass ShippingForm(forms.Form): delivery_type = forms.ChoiceField( choices=[('pickup', 'Store Pickup'), ('delivery', 'Home Delivery')] ) address = forms.CharField(required=False) def clean(self): cleaned_data = super().clean() delivery = cleaned_data.get('delivery_type') address = cleaned_data.get('address') # Address required only for delivery if delivery == 'delivery' and not address: self.add_error('address', 'Address required for delivery') return cleaned_data
Dynamic Required Fields
pythonclass PaymentForm(forms.Form): payment_method = forms.ChoiceField( choices=[('card', 'Credit Card'), ('bank', 'Bank Transfer')] ) card_number = forms.CharField(required=False) bank_account = forms.CharField(required=False) def clean(self): cleaned_data = super().clean() method = cleaned_data.get('payment_method') if method == 'card' and not cleaned_data.get('card_number'): self.add_error('card_number', 'Required for card payments') elif method == 'bank' and not cleaned_data.get('bank_account'): self.add_error('bank_account', 'Required for bank transfers') return cleaned_data
Common Pitfalls
- Setting
required=Trueon conditionally-required fields -- Setrequired=Falseand enforce inclean()instead. - Not clearing irrelevant field data -- Stale data from unused fields may persist.
Best Practices
- Document the conditions -- Add comments explaining which fields are required when.
- Consider multiple form classes -- For complex branching, separate classes may be cleaner.
Summary
Use clean() for conditional validation. Check field dependencies. Add targeted errors with add_error().