Forms
On this page
djust handles forms over WebSocket — no page reloads, no JavaScript, no API layer.
The full forms guide is at guides/forms.md.
Quick Reference
Simple Form (no validation)
from djust import LiveView
from djust.decorators import event_handler
class TodoView(LiveView):
template_name = "todos.html"
def mount(self, request, **kwargs):
self.items = []
@event_handler()
def add_item(self, title="", **kwargs):
if title.strip():
self.items.append(title.strip())
<form dj-submit="add_item">
{% csrf_token %}
<input type="text" name="title" placeholder="New item" />
<button type="submit">Add</button>
</form>
With Django Forms Validation
from django import forms
from djust import LiveView
from djust.forms import FormMixin
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
class ContactView(FormMixin, LiveView):
template_name = "contact.html"
form_class = ContactForm
def form_valid(self, form):
send_email(form.cleaned_data)
self.success_message = "Message sent!"
def form_invalid(self, form):
self.error_message = "Please fix the errors below."
<form dj-submit="submit_form">
{% csrf_token %}
<input name="name" value="{{ form_data.name }}" dj-change="validate_field" />
{% if field_errors.name %}<span>{{ field_errors.name.0 }}</span>{% endif %}
<input name="email" type="email" value="{{ form_data.email }}" dj-change="validate_field" />
{% if field_errors.email %}<span>{{ field_errors.email.0 }}</span>{% endif %}
<button type="submit">Send</button>
</form>
dj-change="validate_field" validates each field on blur — instant inline errors without a full submission.
Editing Existing Records (ModelForm)
class ArticleEditView(FormMixin, LiveView):
template_name = "article_form.html"
form_class = ArticleForm
def mount(self, request, pk=None, **kwargs):
if pk:
self._model_instance = Article.objects.get(pk=pk)
super().mount(request, **kwargs)
def form_valid(self, form):
form.save()
self.success_message = "Saved!"
FormMixin Template Variables
| Variable | Type | Description |
|---|---|---|
form_data | dict | Current field values |
field_errors | dict | Per-field errors {field: [errors]} |
form_errors | list | Non-field errors from clean() ({} until an invalid submit) |
is_valid | bool | Result of last submission |
success_message | str | Success message your view sets (empty by default) |
error_message | str | Error message your view sets (empty by default) |
form_choices | dict | Choices for choice fields, keyed by field name |
The Django form instance is available in Python as self.form_instance; it is not in the template context.
Multi-Step Wizards
For guided multi-step forms, use WizardMixin:
from djust import WizardMixin, LiveView
class SignupWizard(WizardMixin, LiveView):
wizard_steps = [
{"name": "personal", "title": "Personal Info", "form_class": PersonalInfoForm},
{"name": "address", "title": "Address", "form_class": AddressForm},
{"name": "review", "title": "Review"},
]
def on_wizard_complete(self, step_data):
User.objects.create(**step_data["personal"])
See guides/wizards.md for the full wizard guide.
Full Guide
See guides/forms.md for:
- Real-time validation details
form.as_liveauto-rendering- Confirmation dialogs (
dj-confirm) dj-modelvsdj-submitcomparison- Draft mode auto-save (see State Management)
Markdown editor
See the Markdown Editor guide for optional Visual/Markdown editing, native form integration, asset loading, theme variables and editing limitations.