Как придать стиль ярлыку Django crispy-form
Я разрабатываю небольшой проект, используя Django v5 и Bootstrap v5. На данном этапе я просто играю со страницами registration
и login
, но я хотел бы стилизовать форму, используя crispy-form
и crispy FormHelper
. Я могу изменить отображаемую метку, но (пока) мне не удается сделать метку жирной и/или подчеркнутой, чтобы показать, что это обязательное поле (а не использовать звездочку в crispy).
Вот мой файл forms.py
:
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'))
Примечание - закомментированный раздел изменяет стиль input
, а не label
.
и register.html
шаблон
{% 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 %}
Как сделать username label
(и другие метки) bold
и underlined
, в идеале используя класс Bootstrap fw-bold
?
Единственный способ, который я пока нашел, - это изменить класс css requiredField
, добавив элемент style
в base.html непосредственно под ссылкой cdn на Bootstrap, как показано ниже :
<style>
.requiredField {
font-weight:bold;
text-decoration:underline;
}
</style>
Если кто-нибудь знает способ получше, я был бы признателен, если бы он поделился своими знаниями.
Это можно сделать, расширив класс layout.Field
. Мы можем создать наш собственный подкласс, который принимает дополнительный аргумент label_class
, а затем модифицировать метод render
, добавив label_class
к extra_context
. По умолчанию, когда вы делаете что-то вроде этого: self.helper.label_class = 'fw-bold'
это добавляет label_class
в глобальный контекст, и, как вы правильно заметили, это значение будет использоваться для всех меток полей формы. Но с помощью extra_context
мы можем динамически переопределять контекстные переменные для конкретной метки поля.
Здесь будет задан дополнительный контекст . Как только поле будет отображено, исходный контекст будет восстановлен, это реализовано здесь с помощью KeepContext
контекстного менеджера. Вот пример того, как может выглядеть наш пользовательский Field
:
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,
)
А теперь пример формы, в которой мы будем использовать CustomField
для динамического переопределения label_class
обязательных полей для добавления двух классов bootstrap: '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
Результат будет выглядеть следующим образом:
<время работы/>Вот еще один простой пример, где глобально задается label_class = 'fw-bold'
и дополнительно добавляется уникальный цвет для каждой метки поля:
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'
Результат будет выглядеть следующим образом: