Forms
Integrate Django Forms with real-time validation and seamless submission.
Quick Start
1. Create a Django Form
forms.py
1# forms.py
2fromdjangoimport forms
3
4classContactForm(forms.Form):
5 name = forms.CharField(max_length=100)
6 email = forms.EmailField()
7 message = forms.CharField(widget=forms.Textarea)
2. Create a LiveView with FormMixin
views.py
1# views.py
2fromdjustimport LiveView
3fromdjust.formsimport FormMixin
4from.formsimport ContactForm
5
6classContactView(FormMixin, LiveView):
7 template_name = 'contact.html'
8 form_class = ContactForm
9
10 defform_valid(self, form):
11 send_email(to='support@example.com', body=form.cleaned_data['message'])
12 self.success_message = 'Message sent!'
13
14 defform_invalid(self, form):
15 pass # Errors shown automatically
3. Create the Template
templates/contact.html
1<div dj-liveview>
2 {% if success_message %}
3 <div class="alert alert-success">{{ success_message }}</div>
4 {% else %}
5 <form dj-submit="submit">
6 {% csrf_token %}
7
8 <div class="mb-3">
9 <label>Name</label>
10 <input name="name" dj-change="name" value="{{ form.name.value|default:'' }}">
11 {% if field_errors.name %}
12 <div class="error">{{ field_errors.name }}</div>
13 {% endif %}
14 </div>
15
16 <!-- Repeat for other fields -->
17
18 <button type="submit">Send</button>
19 </form>
20 {% endif %}
21</div>
Real-Time Validation
On Blur (dj-change)
Validate when field loses focus:
<input name="email" dj-change="email" value="{{ form.email.value }}">
On Keystroke (dj-input with debounce)
fromdjustimport debounce
classSignupView(FormMixin, LiveView):
@debounce(wait=0.3)
defusername(self, value: str = "", **kwargs):
self.form_data['username'] = value
self.validate_field('username', value)
# Custom async validation
if User.objects.filter(username=value).exists():
self.field_errors['username'] = 'Username already taken'
Custom Validation
defvalidate_field(self, field_name, value, **kwargs):
super().validate_field(field_name, value, **kwargs)
if field_name == 'email':
if not value.endswith('@company.com'):
self.field_errors['email'] = 'Must use company email'
ModelForms
classArticleForm(forms.ModelForm):
classMeta:
model = Article
fields = ['title', 'content']
classArticleCreateView(FormMixin, LiveView):
form_class = ArticleForm
defform_valid(self, form):
article = form.save(commit=False)
article.author = self.request.user
article.save()
self.success = True
Multi-Step Forms
classWizardView(LiveView):
defmount(self, request, **kwargs):
self.step = 1
self.data = {}
defnext_step(self, **kwargs):
if self.validate_current_step():
self.step += 1
defprev_step(self):
if self.step > 1:
self.step -= 1
defsubmit(self, **kwargs):
if self.step == 3 and self.validate_current_step():
self.create_order()
self.success = True
File Uploads
classUploadView(LiveView):
defhandle_upload(self, file=None, **kwargs):
if file:
if file.size > 10 * 1024 * 1024: # 10MB
self.error = 'File too large'
return
fromdjango.core.files.storageimport default_storage
path = default_storage.save(f'uploads/{file.name}', file)
self.uploaded_file = path
Form Styling
Bootstrap 5
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" name="email"
class="form-control {% if field_errors.email %}is-invalid{% endif %}"
dj-change="email" value="{{ form.email.value|default:'' }}">
{% if field_errors.email %}
<div class="invalid-feedback">{{ field_errors.email }}</div>
{% endif %}
</div>
Tailwind
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700">Email</label>
<input type="email" name="email"
class="mt-1 block w-full rounded-md border-gray-300
{% if field_errors.email %}border-red-300{% endif %}"
dj-change="email" value="{{ form.email.value|default:'' }}">
{% if field_errors.email %}
<p class="mt-2 text-sm text-red-600">{{ field_errors.email }}</p>
{% endif %}
</div>
Best Practices
- Always include
- Use
@debouncefor real-time validation - Disable submit button during processing
- Clear form after successful submission
- Handle errors gracefully
Next Steps
- Testing - Test form validation
- API Reference - FormMixin API