31

我需要一些方法来将类属性添加到label_tag()表单字段的方法的输出中。

我看到可以传入attrs字典,并且我已经在 shell 中对其进行了测试,我可以执行以下操作:

for field in form:
    print field.label_tag(attrs{'class':'Foo'})

我会class='Foo'在我的输出中看到 ,但我看不到attrs从模板中添加参数的方法 - 事实上,模板是专门针对这一点设计的,不是吗?

我的表单定义中有没有办法定义要在标签中显示的类?

在表格中,我可以执行以下操作来为输入提供一个类

self.fields['some_field'].widget.attrs['class'] = 'Foo'

我只需要让它也输出类<label />

4

9 回答 9

21

技术1

我对另一个答案的断言提出异议,即过滤器会“不那么优雅”。如您所见,它确实非常优雅。

@register.filter(is_safe=True)
def label_with_classes(value, arg):

    return value.label_tag(attrs={'class': arg})

在模板中使用它同样优雅:

{{ form.my_field|label_with_classes:"class1 class2"}}

技巧2

或者,我发现的一种更有趣的技术是:将 * 添加到必填字段

您为 BoundField.label_tag 创建一个装饰器,该装饰器将在适当设置attrs的情况下调用它。然后你猴子修补 BoundField 以便调用 BoundField.label_tag 调用装饰函数。

from django.forms.forms import BoundField

def add_control_label(f):
    def control_label_tag(self, contents=None, attrs=None):
        if attrs is None: attrs = {}
        attrs['class'] = 'control-label'
        return f(self, contents, attrs) 
    return control_label_tag

BoundField.label_tag = add_control_label(BoundField.label_tag)    
于 2012-07-20T17:49:31.413 回答
11

如何将 CSS 类添加到 forms.py 中的表单字段,例如:

class MyForm(forms.Form):
    title = forms.CharField(widget=forms.TextInput(attrs={'class': 'foo'}))

然后我只需在模板中执行以下操作:

<label for="id_{{form.title.name}}" class="bar">
    {{ form.title }}
</label>

当然,这可以很容易地修改为在模板中的 for 循环标记中工作。

于 2009-12-19T18:16:02.380 回答
8

定义模板标签似乎是解决方案。自定义过滤器也可以,尽管它可能不那么优雅。但是在这两种情况下,您都需要回退到自定义表单呈现。

如果这是一项非常重要的任务;我将创建一个 Mixin,它允许我使用标签类注释表单字段并使用这些类提供表单呈现方法。以便以下代码有效:

{{ form.as_table_with_label_classes }}

但我想问一下;你真的需要标签标签上的类吗?我的意思是 HTML 设计方面。是否绝对有必要在其中添加一个类?难道不能用一些 CSS 来解决,比如:

encapsulating_selector label {
    some-attr: some-value;
}

我有时会在这种情况下使用jQuery如果它有效,它会改进页面,但如果它不起作用,它不会是一场灾难。并保持 HTML 源代码尽可能精简。

于 2009-01-06T08:00:00.127 回答
3

我同意第一个答案,使用 css 可以做到这一点,但是。这是在 django 源代码中的原因是什么?

在 django.forms.forms.py 中有这个定义,显示attrs了标签中显示的代码:

class BoundField(StrAndUnicode): 
    ...
    def label_tag(self, contents=None, attrs=None):
        contents = u'<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, unicode(contents))

_html_output在没有 attrs 的情况下调用此函数:

label = bf.label_tag(label) or ''

因此,django 似乎已部分准备好执行此操作,但实际上并没有使用它。

于 2009-10-31T05:47:09.330 回答
2

有点太晚了,但遇到了类似的问题。希望这对您有所帮助。

class MyForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myfield1'].widget.attrs.update(
            {'class': 'form-control'})
        self.fields['myfield2'].widget.attrs.update(
            {'class': 'form-control'})

    def as_two_col_layout(self):

        return self._html_output(
            normal_row='<div class="form-group"><span class="col-xs-2">%(label)s</span> <div class="col-xs-10">%(field)s%(help_text)s</div></div>',
            error_row='%s',
            row_ender='</div>',
            help_text_html=' <span class="helptext">%s</span>',
            errors_on_separate_row=True)

    class Meta:

        model = mymodel
        fields = ['myfield1', 'myfield2']
于 2015-01-30T11:59:59.683 回答
1
class CustomBoundField(BoundField):
    def label_tag(self, contents=None, attrs=None):
        if self.field.required:
            attrs = {'class': 'required'}
        return super(CustomBoundField, self).label_tag(contents, attrs)

class ImportViewerForm(forms.Form):
    url = fields.URLField(widget=forms.TextInput(attrs={'class': 'vTextField'}))
    type = fields.ChoiceField(choices=[('o', 'Organisation'), ('p', 'Program')], widget=forms.RadioSelect,
                              help_text='Url contain infornation about this type')
    source = fields.ChoiceField(choices=[('h', 'hodex'), ('s', 'studyfinder')], initial='h', widget=forms.RadioSelect)

    def __getitem__(self, name):
        "Returns a BoundField with the given name."
        try:
            field = self.fields[name]
        except KeyError:
            raise KeyError('Key %r not found in Form' % name)
        return CustomBoundField(self, field, name)

class Media:
    css = {'all': [settings.STATIC_URL + 'admin/css/forms.css']}

您需要更改 BoundField 类中的 label_tag 方法,并在表单中使用它

于 2013-08-30T11:08:07.647 回答
0
@register.simple_tag
def advanced_label_tag(field):
    """ Return form field label html marked to fill by `*` """
    classes = []
    attrs = {}
    contents = force_unicode(escape(field.label))

    if field.field.required:
        classes.append(u'required')
        contents = force_unicode('%s <span>*</span>'%escape(field.label))

    if classes:
        attrs['class'] = u' '.join(classes)

    return field.label_tag(contents=contents, attrs=attrs)
于 2011-05-31T18:52:51.863 回答
0

我们也可以使用 {{field.label}} 和 {{field.id_for_label}}

<label class="your_class_name" id="{{form.link.id_for_label}}">{{form.link.label}}</label>

以 HTML 格式呈现 -

<label class="your_class_name" id="id_name">Name</label>
于 2020-11-27T22:59:15.213 回答
0

注意:希望即将到来的 Django 4.0 将使这一切变得更容易,因为它提供了基于模板的表单渲染

直到那时:

OP 要求一种在表单定义中使用BoundField.label_tag()的方法。

user240515user2732686的回答确实提供了一些实施建议,但没有提供任何理由。大多数其他基于自定义模板标签的解决方案都需要我们手动渲染表单字段,因此如果我们只是想使用{{ form }}.

因此,除了所有这些答案之外,这里还尝试提供更多背景信息。

关于 label_tag

表单标签由BaseForm.as_table()as_ul()as_p() 快捷方式通过“私有”BaseForm._html_output()方法呈现,如源代码所示。

这是通过调用来完成的BoundField.label_tag(),如这里所示。label_tag ()方法接受一个attrs带有标记的附加 HTML 属性的参数<label>

但是,问题在于没有, 的BaseForm._html_output()调用,并且没有简单的替代方法来设置参数。label_tag()attrsattrs

如何扩展 label_tag?

Django通过扩展其方法contrib.admin解决了这个问题,从源代码中可以清楚地看出。label_tag()AdminField

为了扩展BoundField.label_tag(),我们可以创建一个自定义的 BoundField

class MyBoundField(forms.BoundField):
    def __init__(self, form, field, name, label_attrs=None):
        super().__init__(form, field, name)
        self.label_attrs = label_attrs

    def label_tag(self, contents=None, attrs=None, label_suffix=None):
        if attrs is None:
            attrs = dict()
        attrs.update(self.label_attrs or {})
        return super().label_tag(contents, attrs, label_suffix)

现在我们可以创建一个带有特定标签属性的绑定字段,但是我们如何处理它呢?

如何使用自定义绑定字段?

绑定字段是使用forms.Field.get_bound_field()实例化的,因此,我们可以重写该方法以返回我们的自定义绑定字段:

class MyField(forms.Field):
    # note typically we would use any of django's forms.Field subclasses
    def __init__(self, *args, **kwargs):
        # we could also set label_attrs here, based on the field properties
        self.label_attrs = kwargs.pop('label_attrs', None)
        super().__init__(*args, **kwargs)

    def get_bound_field(self, form, field_name):
        return MyBoundField(
            form=form, field=self, name=field_name, label_attrs=self.label_attrs)

然后我们可以使用我们的自定义字段Form

class MyForm(forms.Form):
    some_field = MyField(..., label_attrs={'class': 'my-class'})

但是如果我们想对所有的表单域都这样做呢?

如何为所有表单字段使用自定义绑定字段?

最后,Field.get_bound_field()被调用BaseForm.__getitem__()(参见源代码)。这意味着我们可以通过调用 eg 来获得一个绑定字段my_form['some_field']

为了对所有表单字段使用我们的自定义绑定字段,我们可以为表单中的所有字段添加猴子补丁 field.get_bound_field,或者我们可以覆盖表单__getitem__()以忽略get_bound_field()并直接使用MyBoundField

这是一个覆盖的示例,它主要是原始 source的副本,除了以下MyBoundField行:

class MyForm(forms.Form):
    label_attrs = {'class': 'my-class'}
    
    def __getitem__(self, name):
        """Return a MyBoundField with the given name."""
        try:
            field = self.fields[name]
        except KeyError:
            ...  # left out for clarity
        if name not in self._bound_fields_cache:
            self._bound_fields_cache[name] = MyBoundField(
                form=self, field=field, name=name, label_attrs=self.label_attrs)
        return self._bound_fields_cache[name]

最后,这对于一些造型来说似乎麻烦。

于 2021-09-22T13:12:53.263 回答