How to style a Django crispy-form label - Stack Overflow

I'm developing a small project using Django v5 and Bootstrap v5.At this stage I'm just play

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?

Share Improve this question asked Mar 21 at 20:43 Doug ConranDoug Conran 4971 gold badge5 silver badges20 bronze badges 1
  • I know that I can use 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
Add a comment  | 

2 Answers 2

Reset to default 1

This 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

相关推荐

  • How to style a Django crispy-form label - Stack Overflow

    I'm developing a small project using Django v5 and Bootstrap v5.At this stage I'm just play

    7天前
    90

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信