--- name: django-forms description: Django form handling patterns including ModelForm, validation, clean methods, and HTMX form submission. Use when building forms, implementing validation, or handling form submission. --- # Django Forms ## Philosophy - Prefer ModelForm for model-backed forms - Keep validation logic in forms, not views - Always handle and display form errors - Use `commit=False` when you need to modify the instance before saving ## Validation **Field-level** (`clean_`): - Validate and transform a single field - Return the cleaned value or raise `ValidationError` - Use for: format checks, uniqueness, normalization **Cross-field** (`clean`): - Call `super().clean()` first - Access multiple fields via `cleaned_data` - Use `self.add_error(field, message)` for field-specific errors - Use for: password confirmation, conditional requirements ## View Integration - Check `request.method` explicitly - Instantiate form with `request.POST` for POST, empty for GET - Use `form.save(commit=False)` to set additional fields (e.g., author) - Return redirect on success, re-render with form on error **HTMX handling:** - Check `request.headers.get("HX-Request")` for HTMX requests - Return partial template on success/error for HTMX - Use `HX-Trigger` header to notify other components ## Templates - Display `form.non_field_errors` for cross-field errors - Display `field.errors` for each field - Use partial templates (`_form.html`) for HTMX responses - Include loading indicator with `hx-indicator` ## Widgets - Override in `Meta.widgets` dict - Set HTML attributes via `attrs` parameter - Common: `Textarea(attrs={"rows": 5})`, `DateTimeInput(attrs={"type": "datetime-local"})` ## Formsets - Use `inlineformset_factory` for related model collections - Validate both form and formset: `form.is_valid() and formset.is_valid()` - Pass `instance` for editing existing parent objects ## Pitfalls - Validating in views instead of forms - Silently redirecting without checking `is_valid()` - Forgetting `commit=False` when setting related fields - Not displaying form errors to users