I'm developing a small project using Django v5 and Bootstrap v5. At this stage I'm just playing around with the registration
and login
pages but I'd like to style the form using crispy-form
and the crispy FormHelper
. I can change the displayed label but (so far) I've been unable to make the label bold and/or underlined to show that it is a required field (rather than using crispy's asterisk).
For what it is worth here is my forms.py
file:
from django import forms
from django.contrib.auth import get_user_model
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Field, Layout
class LoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'autofocus': 'autofocus'}))
password = forms.CharField(widget = forms.PasswordInput)
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(
label = 'Password',
widget = forms.PasswordInput
)
password2 = forms.CharField(
label = 'Repeat password',
widget = forms.PasswordInput
)
class Meta:
model = get_user_model()
fields = ['username','email','first_name','last_name']
widgets = {
"username": forms.TextInput(attrs={'autofocus': 'autofocus'}),
}
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError("Passwords don't match!")
return cd['password2']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.fields['username'].label= "User Name"
self.fields['username'].help_text= "This will be your Login ID and must be unique"
#self.helper.layout = Layout(
#Field('username', label='User Name - Doug', css_class="fs-2")
#)
self.helper.add_input(Submit('submit', 'Register'))
Note - the commented out section changes the style of the input
, not the label
.
and register.html
template
{% extends "registration/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h2>Registration Form</h2>
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
{% crispy form %}
</fieldset>
<div class="pb-4">
<small class="text-muted">Required fields are marked by *</small>
</div>
</form>
</div>
{% endblock %}
How can I make the username label
(and other labels) bold
and underlined
, ideally using Bootstrap's fw-bold
class?
I'm developing a small project using Django v5 and Bootstrap v5. At this stage I'm just playing around with the registration
and login
pages but I'd like to style the form using crispy-form
and the crispy FormHelper
. I can change the displayed label but (so far) I've been unable to make the label bold and/or underlined to show that it is a required field (rather than using crispy's asterisk).
For what it is worth here is my forms.py
file:
from django import forms
from django.contrib.auth import get_user_model
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Field, Layout
class LoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'autofocus': 'autofocus'}))
password = forms.CharField(widget = forms.PasswordInput)
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(
label = 'Password',
widget = forms.PasswordInput
)
password2 = forms.CharField(
label = 'Repeat password',
widget = forms.PasswordInput
)
class Meta:
model = get_user_model()
fields = ['username','email','first_name','last_name']
widgets = {
"username": forms.TextInput(attrs={'autofocus': 'autofocus'}),
}
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError("Passwords don't match!")
return cd['password2']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.fields['username'].label= "User Name"
self.fields['username'].help_text= "This will be your Login ID and must be unique"
#self.helper.layout = Layout(
#Field('username', label='User Name - Doug', css_class="fs-2")
#)
self.helper.add_input(Submit('submit', 'Register'))
Note - the commented out section changes the style of the input
, not the label
.
and register.html
template
{% extends "registration/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h2>Registration Form</h2>
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
{% crispy form %}
</fieldset>
<div class="pb-4">
<small class="text-muted">Required fields are marked by *</small>
</div>
</form>
</div>
{% endblock %}
How can I make the username label
(and other labels) bold
and underlined
, ideally using Bootstrap's fw-bold
class?
2 Answers
Reset to default 1This can be done by extending the layout.Field
class. We can create our own subclass that takes an additional label_class
argument, and then we modify the render
method by adding label_class
to extra_context
. By default, when you do something like this: self.helper.label_class = 'fw-bold'
this adds label_class
to the global context and as you correctly note, this value will be used for all form field labels. But with extra_context
we can override dynamically the context variables for a particular field label.
The extra context will be set here. Once the field is rendered, the original context will be restored, this is implemented here using the KeepContext
context manager. Here is an example of what our custom Field
might look like:
from crispy_forms.layout import Field
from crispy_forms.utils import TEMPLATE_PACK
class CustomField(Field):
def __init__(
self,
*fields,
css_class=None,
wrapper_class=None,
template=None,
label_class='',
**kwargs) -> None:
super().__init__(
*fields,
css_class=css_class,
wrapper_class=wrapper_class,
template=template,
**kwargs,
)
self.label_class = label_class
def render(
self,
form,
context,
template_pack=TEMPLATE_PACK,
extra_context=None,
**kwargs):
extra_context = extra_context or {}
context_label_class = context.get('label_class', '')
# Merge FormHelper().label_class and CustomField().label_class
label_class = self.label_class + ' ' + context_label_class
extra_context['label_class'] = label_class.strip()
return super().render(
form=form,
context=context,
template_pack=template_pack,
extra_context=extra_context,
**kwargs,
)
And now an example form where we will use CustomField
to dynamically override label_class
for required fields to add two bootstrap classes: 'fw-bold', 'text-decoration-underline'
:
from functools import cached_property
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Field, Layout, Submit
from django import forms
from django.contrib.auth import get_user_model
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(
label = 'Password',
widget = forms.PasswordInput
)
password2 = forms.CharField(
label = 'Repeat password',
widget = forms.PasswordInput
)
class Meta:
model = get_user_model()
fields = ['username', 'email', 'first_name', 'last_name']
widgets = {
"username": forms.TextInput(attrs={'autofocus': 'autofocus'}),
}
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError("Passwords don't match!")
return cd['password2']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].label= "User Name"
self.fields['username'].help_text= (
"This will be your Login ID and must be unique"
)
self.helper.add_input(Submit('submit', 'Register'))
@cached_property
def helper(self):
def make_field(f_name: str, is_required: bool) -> Field:
return (
Field(f_name) if not is_required
else CustomField(f_name, label_class=label_class)
)
helper = FormHelper()
label_class = ' '.join(['fw-bold', 'text-decoration-underline'])
helper.layout = Layout(
*(
make_field(field_name, field_obj.required)
for field_name, field_obj in self.fields.items()
)
)
return helper
The result will look like this:
Here's another simple example where globally set label_class = 'fw-bold'
and additionally add a unique color for each field label:
class ExampleForm(forms.Form):
foo = forms.CharField(max_length=100)
bar = forms.CharField(max_length=100)
baz = forms.CharField(max_length=100)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
CustomField('foo', label_class='text-info'),
CustomField('bar', label_class='text-danger'),
CustomField('baz', label_class='text-success'),
)
self.helper.label_class = 'fw-bold'
The result will look like this:
And one more bonus solution that came to my mind. It is similar to yours, but more versatile and flexible. You can use layout.Field
with wrapper_class
attribute, for example like this:
self.helper.layout = Layout(
Field('field_name', wrapper_class='bold-underline-label'),
)
And apply styles to label
using Child combinator
:
<style>
.bold-underline-label > label {
font-weight: bold;
text-decoration: underline;
}
</style>
A reply to your comment:
I've found that when adding a Layout to FormHelper the page then only shows those fields specified in the Layout. Different question, I know, but can I include all fields in the Layout without having to type them all out?
You can create a layout with all your form fields using self.helper = FormHelper(self)
, this passes the form instance as the first argument and creates a layout that includes all form fields. Then we can simply replace any fields we want in the layout. Here's a quick example:
class ExampleForm(forms.Form):
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Here we pass an instance of the form to build the layout with
# all the fields.
self.helper = FormHelper(self)
layout_fields = self.helper.layout.fields
# Replace in the layout those fields where we need to add some
# additional classes, in our case these are required fields.
for i, (field_name, field_obj) in enumerate(self.fields.items()):
# It can be any condition, and you can add any other classes
# for any fields. For example:
# `if field_name == 'username': Field(..., wrapper_class='your-cls')`
if field_obj.required:
layout_fields[i] = Field(
field_name,
wrapper_class='bold-underline-label',
)
The only way I've found, so far, is to modify the css class requiredField
by adding a style
element in base.html immediately below the cdn link to Bootstrap, as in :
<style>
.requiredField {
font-weight:bold;
text-decoration:underline;
}
</style>
If anyone knows any better way I'd be grateul if they could shar their knowledge.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744334083a4569028.html
self.helper.label_class = 'fw-bold'
- but that changes ALL labels. I only want to change those labels that are for required inputs. – Doug Conran Commented Mar 21 at 21:07