Как установить класс css метки в объявлении формы django?
Я использую django-uniform и для использования некоторых единообразных функций, я ищу способ добавить класс css непосредственно из объявления формы (для виджетов независимых).
(в качестве бонуса, здесь мой многоразовый только для чтения домашний миксов)...
from django import forms
def _get_cleaner(form, field):
def clean_field():
return getattr(form.instance, field, None)
return clean_field
class UniformROMixin(forms.BaseForm):
"""
UniformROMixin, inherits to turn some fields read only
- read_only = list of field names.
"""
def __init__(self, *args, **kwargs):
super(UniformROMixin, self).__init__(*args, **kwargs)
if hasattr(self, "read_only"):
if self.instance and self.instance.pk:
for field in self.read_only:
self.fields[field].widget.attrs['readonly'] = True
self.fields[field].widget.attrs['class'] += "readOnly"
# here I would like to set css class of the label
# created from the self.fields[field].label string
setattr(self, "clean_" + field, _get_cleaner(self, field))
Мой единственный способ - добавить немного javascript в свой шаблон общей формы и добавить классы вручную.
Любая блестящая идея?
Ответы
Ответ 1
Я нашел этот фрагмент, который может быть хорошим ответом:
Как добавить класс css и "*" в метки обязательных полей
здесь адаптация к моим потребностям (еще не проверено, я отредактирую сообщение после этого):
from django.utils.html import escape
def readonly_cssclass_adder(bound_field, label_content, label_attrs):
if 'readonly' in bound_field.field.widget.attrs:
if 'class' in attrs:
label_attrs['class'] += " readOnly"
else:
label_attrs['class'] = "readOnly"
return label_content, label_attrs
def add_required_label_tag(original_function, tweak_foos=None):
if not tweak_foos:
return original_function
def required_label_tag(self, contents=None, attrs=None):
contents = contents or escape(self.label)
if attrs is None:
attrs = {}
for foo in tweak_foos:
contents, attrs = foo(self, contents, attrs)
return original_function(self, contents, attrs)
return required_label_tag
def decorate_bound_field():
from django.forms.forms import BoundField
BoundField.label_tag = add_required_label_tag(BoundField.label_tag,
tweak_foos=[readonly_cssclass_adder])
Если у вас есть лучшее решение, которое не изменяет весь класс BoundField, который я все еще слушаю.
изменить: может быть связан с django единообразным способом обработки требуемого поля, но, похоже, он не вызывает readonly_cssclass_adder
. Но я нашел другое и более легкое решение, мой виджет readOnly автоматически превратился в readOnly ctrlHolder
Это дополнение - мой любимый ответ:
edit 2: Другим способом, который я выбрал в конце, было "переопределить" шаблон uni_form/field.html
, который не вызывает BoundField.label_tag. Поэтому я проверил здесь состояние поля.
<label for="{{ field.auto_id }}"{% if field.field.required %}
class="requiredField{% if field.widget.attrs.readonly %} readOnlyLabel{% endif %}"
{% else %}{% if field.widget.attrs.readonly %}class="readOnlyLabel"{% endif %}{% endif %}>
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
Ответ 2
У виджета есть аргумент ключевого слова attrs
, который принимает dict
, который может определять атрибуты для элемента ввода, который он отображает. У форм также есть некоторые атрибуты, которые вы можете определить, чтобы изменить способ отображения формы Django. Возьмем следующий пример:
class MyForm(forms.Form):
error_css_class = 'error'
required_css_class = 'required'
my_field = forms.CharField(max_length=10,
widget=forms.TextInput(attrs={'id': 'my_field',
'class': 'my_class'}))
Это работает в любом классе Widget
. К сожалению, нет простого способа изменить, как Django создает метки, если вы просто делаете {{ field }}
. К счастью, вы немного играете с объектом формы в шаблоне:
<form>
{% for field in form %}
<label class="my_class" for="{{ field.name }}">{{ field.label }}</label>
{{ field }}
{% endfor %}
<button type="submit">Submit</button>
</form>
Затем вы всегда можете добавлять произвольные атрибуты к объектам, с которыми работаете:
# In a view...
form = MyForm()
form.label_classes = ('class_a', 'class_b', )
# Or by hijacking ```__init__```
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.my_field = forms.CharField(max_length=10,
widget=forms.TextInput(attrs={'id': 'my_field',
'class': 'my_class'}))
self.my_field.label_classes = ('class_a', 'class_b', )
super(MyForm, self).__init__(*args, **kwargs)
Отредактируйте свой шаблон с помощью формы в контексте и в шаблоне, который вы можете сделать:
<form>
{% for field in form %}
<label class="{% for class in field.label_classes %}{{ class }} {% endfor %}"
for="{{ field.name }}">{{ field.label }}</label>
{{ field }}
{% endfor %}
<button type="submit">Submit</button>
</form>
Какая бы ни была ваша фантазия.
Ответ 3
Немного настраиваемая опция, основанная на решении @xj9, используемом с полем ManyToMany и Bootstrap .checkbox-inline
. Работает так же для переключателя с .radio-inline
.
form.py
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['m2mfield'] = forms.ModelMultipleChoiceField(
queryset=Model.objects.all().order_by('name'),
required=True,
widget=forms.CheckboxSelectMultiple())
template.html
<div class="col-sm-9">
{% for field in form.m2mfield %}
<label class="checkbox-inline" for="{{ field.name }}">{{ field.label }}</label>
{{ field }}
{% endfor %}
</div>