如何在 django 表单声明中设置标签的 css 类?

发布于 2024-11-28 12:35:34 字数 1129 浏览 2 评论 0原文

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

(作为奖励,这里是我的可重复使用的只读自制 mixin 片段...)

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

有什么绝妙的主意吗?

I'm using django-uniform and to use some uniform features, I'm looking for a way to add css class directly from form declaration (for independents widgets).

(as a bonus, here my reusable read-only home made mixin snippet...)

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))

My only way for now is to add a bit of javascript on my generic form template and add classes manualy.

Any brillant idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜还是长夜 2024-12-05 12:35:34

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

随心所欲。

Widgets have an attrs keyword argument that take a dict which can define attributes for the input element that it renders. Forms also have some attributes you can define to change how Django displays your form. Take the following example:

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'}))

This works on any Widget class. Unfortunately, there isn't an easy way to change how Django renders labels if you just do {{ field }}. Luckily, you play with the form object a little bit in the template:

<form>
    {% for field in form %}
        <label class="my_class" for="{{ field.auto_id }}">{{ field.label }}</label>
        {{ field }}
    {% endfor %}
    <button type="submit">Submit</button>
</form>

Then again, you can always add arbitrary attributes to the objects you're working with:

# 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)

Render your template with the form in context, and in the template you can do:

<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>

Whatever suits your fancy.

别理我 2024-12-05 12:35:34

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

How to add css class and " *”到必填字段的标签

这里适应我的需求(尚未测试,完成后我将编辑帖子):

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< /code> 不调用 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>

I found this snippet which may be a good answer:

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

here an adaptation to my needs (not tested yet, I'll edit the post once done):

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])

If you have a better solution which don't tweak all the BoundField class I'm still listening.

edit:
may be linked to django uniform way to handle required field but it seems to don't call readonly_cssclass_adder. But I found an other and easyer solution, my readOnly widget automatically turned readOnly ctrlHolder

This addition is my favorite response for now:

edit 2: The other way I choose at end was to "override" the uni_form/field.html template which don't call BoundField.label_tag. So I checked here field state.

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文