【问题标题】:How to set css class of a label in a django form declaration?如何在 django 表单声明中设置标签的 css 类?
【发布时间】:2011-10-21 00:16:56
【问题描述】:

我正在使用 django-uniform 并使用一些统一的功能,我正在寻找一种直接从表单声明添加 css 类的方法(用于独立小部件)。

(作为奖励,这是我的可重复使用的只读自制 mixin sn-p...)

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 并手动添加类。

有什么绝妙的主意吗?

【问题讨论】:

  • 我不知道在表单声明中添加 css 类的方法,但我使用过:pypi.python.org/pypi/django-widget-tweaks 方便地将属性添加到模板中的标签标签和表单元素等内容在有意义的情况下进行调整。
  • 感谢您的建议。就我而言,我没有完全处理由 django-uniform 完成的模板部分。我仍然可以看到小部件的“渲染”方法是如何工作的并覆盖它......

标签: django django-forms django-crispy-forms


【解决方案1】:

我发现这个 sn-p 可能是一个很好的答案:

How to add css class and "*" to required fields's labels

这里根据我的需要进行调整(尚未测试,完成后我会编辑帖子):

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

这个补充是我现在最喜欢的回应:

编辑 2:我最后选择的另一种方法是“覆盖”不调用 BoundField.label_tag 的 uni_form/field.html 模板。所以我在这里检查了字段状态。

<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 类。不幸的是,如果您只是执行{{ field }},则没有一种简单的方法可以更改 Django 呈现标签的方式。幸运的是,您在模板中稍微使用了表单对象:

    <form>
        {% for field in form %}
            <label class="my_class" for="{{ field.auto_id }}">{{ 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.auto_id }}">{{ field.label }}</label>
            {{ field }}
        {% endfor %}
        <button type="submit">Submit</button>
    </form>
    

    随你喜欢。

    【讨论】:

    • 优秀的解决方案!对于那些尝试使用它的人来说,第一行应该是{% for field in form.myfield %}
    • Field 对象不可迭代
    • @xj9:这在 ModeForm 中如何工作?当我像 self.field 一样访问它时,它会抛出一个错误,当我向 self.fields[field] 添加一个属性时,它不会显示出来......
    猜你喜欢
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多