25

我正在使用 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 并手动添加类。

有什么绝妙的主意吗?

4

2 回答 2

41

小部件有一个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.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>

随心所欲,随心所欲。

于 2014-05-09T03:38:04.967 回答
3

我发现这个片段可能是一个很好的答案:

如何将 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

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

编辑 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>
于 2011-08-06T15:07:13.317 回答