在Django Forms中定义CSS类


192

假设我有一个表格

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

有没有一种方法可以在每个字段上定义CSS类,以便可以在渲染页面中基于类使用jQuery?

我希望不必手动构建表单。


9

10
@skyl我认为这是在django文档中不容易找到的指示。我也浏览并进行了几次Google搜索,但都找不到此搜索,因此我很高兴看到这个问题,并且得到了我的好评。
2012年

我知道这是一个旧线程,但是在Django表单字段中现在有一个id_fieldname类。
ratsimihah 2013年

1
在尊重现有字段类的同时,如何在模板内为表单字段定义类,请参见以下答案
dimyG 2016年

Answers:


182

另一种不需要更改python代码的解决方案,因此对于设计人员和一次性演示更改更好:django-widget-tweaks。希望有人会发现它有用。


61
唯一理智的解决办法,我必须说。谢谢!。Python代码,尤其是在表单的定义中,是放置样式的最后一个位置-这些绝对属于模板。
鲍里斯·切尔文科夫

5
这是一个很棒的图书馆!可惜这个答案被埋在了底部。
克里斯·拉卡斯

1
非常适合设计师!:-)
hobbes3'4

1
优秀的!我已经开发了一些过滤器来执行这些操作,但是该项目功能更强大。谢谢!
msbrogli 2012年

1
实际上,它也适用于Jinja2 :-)我更改了安全文件的顺序,并添加了括号,而不是冒号{{myform.email | add_class(“ css_class_1 css_class_2”)| safe}},谢谢您的编写。它应该是Django的一部分。
David Dehghan


78

这是在类中声明字段后将类定义添加到小部件的另一种解决方案。

def __init__(self, *args, **kwargs):
    super(SampleClass, self).__init__(*args, **kwargs)
    self.fields['name'].widget.attrs['class'] = 'my_class'

4
对于ModelForms,这通常会更好,因为您不需要知道所使用的默认表单字段,并且可以根据运行时条件动态设置不同的类。比元编码黑客更
干净

1
假设您要为表单中的每个字段输入一个信息,通常情况并非如此。表单不必一定要与模型绑定-它可能要与许多模型绑定。在模型字段和表单字段具有1:1关系的情况下,是的,ModelForm是更好的选择。
ashchristopher

44

使用django-widget-tweaks,它易于使用并且效果很好。

否则,可以使用自定义模板过滤器来完成此操作。

考虑到您以这种方式呈现表单:

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
</form>

form.subject是具有as_widget方法的BoundField的实例。

您可以在“ my_app / templatetags / myfilters.py”中创建自定义过滤器“ addcss”

from django import template

register = template.Library()

@register.filter(name='addcss')
def addcss(value, arg):
    css_classes = value.field.widget.attrs.get('class', '').split(' ')
    if css_classes and arg not in css_classes:
        css_classes = '%s %s' % (css_classes, arg)
    return value.as_widget(attrs={'class': css_classes})

然后应用您的过滤器:

{% load myfilters %}
<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject|addcss:'MyClass' }}
    </div>
</form>

然后,将使用“ MyClass” css类呈现form.subjects。

希望能有所帮助。

编辑1

  • 根据dimyG的答案更新过滤器

  • 添加django-widget-tweak链接

编辑2

  • 根据Bhyd的评论更新过滤器

3
这很棒!它是DRY,它将显示层与控制层分开。向我+1!
alekwisnia

1
但是,现在我注意到了一个缺点。如果我在窗口小部件attrs中定义类,则此“ addcss”过滤器将覆盖它们。您有任何想法如何合并吗?
alekwisnia

1
我的意思是,as_widget()会覆盖attrs。如何确保它使用现有的属性并用新属性扩展它们?
alekwisnia

关于如何尊重现有字段类的问题,请参见以下答案
dimyG

get('class', None).split(' ')如果标签没有将失败具有类属性,如None被返回。将其更改为get('class', '').split(' ')有效
dtasev

32

扩展指向docs.djangoproject.com的方法:

class MyForm(forms.Form): 
    comment = forms.CharField(
            widget=forms.TextInput(attrs={'size':'40'}))

我认为必须了解每个字段的本机窗口小部件类型很麻烦,并且认为仅将类名放在表单字段上就覆盖默认值很有趣。这似乎为我工作:

class MyForm(forms.Form): 
    #This instantiates the field w/ the default widget
    comment = forms.CharField()

    #We only override the part we care about
    comment.widget.attrs['size'] = '40'

对我来说,这似乎有点清洁。


这恰好是其他人在很久以前所说的,只是您使用的是“大小”而不是“等级”。
克里斯·摩根

3
@Chris Morgan实际上,他是第一个建议在Form声明本身中使用“ comment.widget.attrs”的人(而不是搞乱init或在视图中使用它)。
DarwinSurvivor

29

如果您希望表单中的所有字段都继承某个类,则只需定义一个父类,该类从继承forms.ModelForm,然后从该类继承

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'someClass'


class WhateverForm(BaseForm):
    class Meta:
        model = SomeModel

这帮助我将'form-control'类自动添加到应用程序所有形式的所有字段中,而无需添加代码复制。


1
请以大写字母开头类的名称(同样,BaseForm似乎更合适)
Alvaro

16

这是更改视图的简单方法。在将其传递到模板之前,在视图中添加以下内容。

form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}

14

只需将类添加到表单中,如下所示。

class UserLoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(
        attrs={
        'class':'form-control',
        'placeholder':'Username'
        }
    ))
    password = forms.CharField(widget=forms.PasswordInput(
        attrs={
        'class':'form-control',
        'placeholder':'Password'
        }
    ))

5

这是上述内容的一种变体,它将为所有字段提供相同的类(例如,jQuery的圆角效果很好)。

  # Simple way to assign css class to every field
  def __init__(self, *args, **kwargs):
    super(TranslatedPageForm, self).__init__(*args, **kwargs)
    for myField in self.fields:
      self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'


2

如果您想向模板中的表单字段(而不是view.py或form.py中)添加类,例如,要在不覆盖其第三方视图的情况下修改第三方应用程序,则可以按照以下说明过滤模板在查尔斯泰克 回答很方便。但是在此答案中,模板过滤器会覆盖该字段可能具有的所有现有类。

我尝试将其添加为编辑内容,但建议将其写为新答案。

因此,这是一个尊重字段现有类的模板标记:

from django import template

register = template.Library()


@register.filter(name='addclass')
def addclass(field, given_class):
    existing_classes = field.field.widget.attrs.get('class', None)
    if existing_classes:
        if existing_classes.find(given_class) == -1:
            # if the given class doesn't exist in the existing classes
            classes = existing_classes + ' ' + given_class
        else:
            classes = existing_classes
    else:
        classes = given_class
    return field.as_widget(attrs={"class": classes})

感谢您的建议。因此,我使用一种更加“ pythonic”的方法来编辑答案。
查尔斯

太棒了!,这就是我想要的
ugali soft

1

事实证明,您可以在表单构造函数(init函数)中或在启动表单类之后执行此操作。如果您不编写自己的表单并且该表单来自其他地方,则有时需要这样做-

def some_view(request):
    add_css_to_fields = ['list','of','fields']
    if request.method == 'POST':
        form = SomeForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks/')
    else:
        form = SomeForm()

    for key in form.fields.keys():
        if key in add_css_to_fields:
            field = form.fields[key]
            css_addition = 'css_addition '
            css = field.widget.attrs.get('class', '')
            field.widget.attrs['class'] = css_addition + css_classes

    return render(request, 'template_name.html', {'form': form})

1

您还可以使用Django Crispy Forms,这是定义表单的好工具,以防您需要使用Bootstrap或Foundation这样的CSS框架。在那里为表单字段指定类很容易。

您的表单类会这样:

from django import forms

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions

class SampleClass(forms.Form):
    name = forms.CharField(max_length=30)
    age = forms.IntegerField()
    django_hacker = forms.BooleanField(required=False)

    helper = FormHelper()
    helper.form_class = 'your-form-class'
    helper.layout = Layout(
        Field('name', css_class='name-class'),
        Field('age', css_class='age-class'),
        Field('django_hacker', css-class='hacker-class'),
        FormActions(
            Submit('save_changes', 'Save changes'),
        )
    )
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.