【问题标题】:Define css class in django Forms在 django Forms 中定义 css 类
【发布时间】:2023-03-09 12:26:01
【问题描述】:

假设我有一个表格

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

有没有办法让我在每个字段上定义 css 类,以便我可以在渲染页面中使用基于类的 jQuery?

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

【问题讨论】:

  • 哇,大家都投这个票吗? docs.djangoproject.com/en/dev/ref/forms/widgets/…
  • @skyl 我认为这表明在 django 文档中很难找到它。我也浏览并进行了几次谷歌搜索,但找不到这个,所以我很高兴这个问题,它得到了我的支持。
  • 我知道这是一个旧线程,但在 Django 表单字段中现在有一个 id_fieldname 类。
  • 参见this answer,了解如何在尊重现有字段类的同时为模板内的表单字段定义类

标签: python django django-forms


【解决方案1】:

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

【讨论】:

  • only 理智的解决方案,我必须说。谢谢!。 Python 代码,尤其是在表单的定义中,是最后放置样式的地方——这些绝对属于模板。
  • 这是一个很棒的图书馆!很遗憾,这个答案被埋在了底部。
  • 太棒了!我已经开发了一些过滤器来做这些事情,但是这个项目更强大。谢谢!
  • 实际上它也适用于 Jinja2 :-) 我更改了安全文件过滤器的顺序并添加了括号而不是冒号 {{ myform.email|add_class("css_class_1 css_class_2")|safe }} 感谢您的写作这。它应该是 Django 的一部分。
  • 即使对于开发人员来说,也确实觉得模板是合适的地方。
【解决方案2】:

回答了我自己的问题。 叹息

http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs

我没有意识到它被传递到小部件构造函数中。

【讨论】:

  • 这是否意味着它不能与 ModelForm 类一起使用?
  • 不,您只需要在模型表单中显式定义表单字段,以便您可以定义小部件。或者使用下面列出的解决方案,以避免不得不使用表单字段。
【解决方案3】:

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

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

【讨论】:

  • 对于 ModelForms,这通常会更好,因为您不需要知道正在使用的默认表单字段,并且您可以根据运行时条件动态设置不同的类。比元编码黑客更干净...
  • 这假设您希望表单中的每个字段都有一个输入,但通常情况并非如此。表单不一定与模型相关联 - 它可能与许多模型相关联。如果模型字段和表单字段是 1:1 的关系,那么是的,ModelForm 是一个更好的选择。
【解决方案4】:

使用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 是 BoundField 的一个实例,它具有 as_widget 方法。

您可以在“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>

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

希望对您有所帮助。

编辑 1

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

  • 添加 django-widget-tweak 链接

编辑 2

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

【讨论】:

  • 这太棒了!它是干燥的,它将显示层与控制层分开。来自我的 +1!
  • 然而,现在我注意到了一个缺点。如果我在小部件属性中定义类,那么它们会被这个“addcss”过滤器覆盖。你有什么想法如何合并吗?
  • 我的意思是,as_widget() 会覆盖 attrs。如何确保它使用现有的 attrs 并用新的 attrs 扩展它们?
  • 参见this answer,了解如何尊重现有的字段类
  • get('class', None).split(' ') 将失败,如果标签 not 具有类属性,因为返回了 None。将其更改为 get('class', '').split(' ') 有效
【解决方案5】:

扩展指向 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'

这对我来说似乎更干净一些。

【讨论】:

  • 这正是其他人在很久以前所说的,只是您使用的是“大小”而不是要求的“类”。
  • @Chris Morgan 实际上,他是第一个建议在表单声明本身中使用“comment.widget.attrs”的人(而不是弄乱 init 或在视图中这样做)。
【解决方案6】:

如果你想让表单中的所有字段都继承某个类,你只需定义一个父类,它继承自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' 类自动添加到我的应用程序所有表单的所有字段中,而无需添加代码复制。

【讨论】:

  • 请以大写开头类名(另外,BaseForm 似乎更好的名称)
【解决方案7】:

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

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

【讨论】:

    【解决方案8】:

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

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

    【讨论】:

      【解决方案9】:

      你可以试试这个..

      class SampleClass(forms.Form):
        name = forms.CharField(max_length=30)
        name.widget.attrs.update({'class': 'your-class'})
      ...
      

      更多信息请见:Django Widgets

      【讨论】:

        【解决方案10】:

        这是上面的一个变体,它将为所有字段提供相同的类(例如 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'
        

        【讨论】:

          【解决方案11】:

          如果您想将类添加到表单的字段模板中(不在 view.py 或 form.py 中),例如您想修改 3rd 方应用程序而不覆盖他们的视图,然后在 Charlesthk answer 中描述的模板过滤器非常方便。但是在这个答案中,模板过滤器会覆盖该字段可能具有的任何现有类。

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

          所以,这里有一个模板标签,它尊重该字段的现有类:

          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”的方法相应地编辑了我的答案。
          • 太棒了!!,这就是我想要的
          【解决方案12】:

          事实证明,您可以在表单构造函数(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})
          

          【讨论】:

            【解决方案13】:

            您也可以使用Django Crispy Forms,如果您想使用一些 CSS 框架,如 Bootstrap 或 Foundation,它是定义表单的好工具。在那里为您的表单字段指定类很容易。

            你的表单类会这样:

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

            【讨论】:

              【解决方案14】:

              您可以获得各种输入字段的样式选项here

              小部件是 Django 对 HTML 输入元素的表示。小部件处理 HTML 的呈现,以及从与小部件对应的 GET/POST 字典中提取数据。

              email = forms.EmailField(label='Your email', widget=forms.EmailInput(attrs={'class': 'ui segment teal'}))
              

              【讨论】:

                猜你喜欢
                • 2012-01-18
                • 2013-10-19
                • 1970-01-01
                • 2011-10-29
                • 2015-06-24
                • 2018-07-15
                • 2014-06-22
                • 2023-01-31
                • 2012-06-21
                相关资源
                最近更新 更多