Pegasus ships with some extensions to Django forms to integrate with different CSS frameworks and add some extensions.
You can use default Django form rendering for forms, but if you want all the built-in style support,
you should instead use the utilities in the form_tags
module.
To use it, first include form_tags
in any Django template file:
{% load form_tags %}
Then, you can render a form using the render_form_fields
template tag.
Here is a basic example:
<form method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{% render_form_fields form %}
<div class="mt-2">
<button class="pg-button-primary" type="submit">{% translate "Submit Form" %}</button>
</div>
</form>
You can also render individual fields using render_field
:
<form method="POST" action="{% url 'account_change_password' %}" class="password_change">
{% csrf_token %}
{{ form.non_field_errors }}
{% render_field form.username %}
{% render_field form.password %}
<div class="mt-2">
<input class="pg-button-primary" type="submit" value="{% translate 'Login' %}">
</div>
</form>
Added in version 2023.6
The form rendering helpers also support adding attributes, which can be useful to add Alpine.js to make a form more dynamic.
For example, you can bind a form value to an alpine model by passing it in attrs
like this:
class ExampleFormAlpine(forms.Form):
YES_NO_OTHER = (
("yes", gettext("Yes")),
("no", gettext("No")),
("other", gettext("Other")),
)
like_django = forms.ChoiceField(
label=gettext("Do you like Django?"),
choices=YES_NO_OTHER,
widget=forms.Select(attrs={"x-model": "likeDjango"}), # this line will bind the value to an alpine model
)
Then in the HTML template you have to add an alpine model to the form:
<form method="post" x-data="{ likeDjango: '{{ form.like_django.data|default:"yes" }}', styleValue: '{{ form.styled_options.data|default:"regular" }}' }">
<!-- other fields here -->
{% render_field form.like_django %} <!-- this will bind to `likeDjango` above -->
The render_field
tags support two special syntaxes to make using alpine easier:
- Any attribute starting with
x
will be automatically converted tox-
. - Double underscores (
__
) will be replaced with colons (:
).
The following example alpine form and template (which also ship with Pegasus, available at http://localhost:8000/pegasus/forms/alpine/) demonstrate this usage, including hiding/showing a field based on the value of another field, rendering field values in labels, and changing the style of a field based on its value.
Django form class:
class ExampleFormAlpine(forms.Form):
YES_NO_OTHER = (
("yes", gettext("Yes")),
("no", gettext("No")),
("other", gettext("Other")),
)
STYLES = (
("regular", gettext("Normal")),
("success", gettext("Success")),
("danger", gettext("Danger")),
)
like_django = forms.ChoiceField(
label=gettext("Do you like Django?"),
help_text=gettext("Try choosing 'other' to see unhiding a form field based on a value."),
choices=YES_NO_OTHER,
widget=forms.Select(attrs={"x-model": "likeDjango"}),
)
like_django_other = forms.CharField(label=gettext("Please specify more details about your answer."))
styled_options = forms.ChoiceField(
label=gettext("Styled Options"),
help_text=gettext("Try picking an option to see how you can style a component based on its value."),
choices=STYLES,
widget=forms.Select(attrs={"x-model": "styleValue"}),
)
Django template:
<form method="post" x-data="{ likeDjango: '{{ form.like_django.data|default:"yes" }}', styleValue: '{{ form.styled_options.data|default:"regular" }}' }">
{% csrf_token %}
{% render_field form.like_django %}
{% render_field form.like_django_other xshow="likeDjango === 'other'" xcloak='True' %}
{% render_field form.styled_options xbind__class="'pg-bg-' + styleValue" %}
<p class="mt-4">You can also use alpine to display selected values.
<em>
Like Django: <strong x-text="likeDjango"></strong>,
Style: <strong x-text="styleValue"></strong>
</em>
</p>
<input type="submit" value="Save Data" class="pg-button-secondary mt-2">
</form>