【问题标题】:Django: Adding CSS classes when rendering form fields in a templateDjango:在模板中呈现表单字段时添加 CSS 类
【发布时间】:2011-05-06 16:05:30
【问题描述】:

我正在像{{ form.first_name }} 这样的模板中输出表单的字段,我想向它添加一个类(例如蓝图的 span-x-类)。所以我想知道是否有一个很好的现成解决方案(模板过滤器),我可以在时尚{{ form.first_name|add_class:"span-4" }} 中使用它? (我只是想知道 Django 的开发人员或其他人是否在我自己不知情的情况下想到了这一点)

【问题讨论】:

    标签: python django forms


    【解决方案1】:

    为 python3 更新

    更新很简单,只需要在 print 上加上括号并将 unicode(value) 更改为 str(value),我还快速将 'class="%s">' 更改为 fstring。

    import re
    from django.utils.safestring import mark_safe
    from django import template
    register = template.Library()
    
    class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
    @register.filter
    def add_class(value, css_class):
        string = str(value)
        match = class_re.search(string)
        if match:
            m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                                                        css_class, css_class), 
                                                        match.group(1))
            print (match.group(1))
            if not m:
                return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
                                              string))
        else:
            return mark_safe(string.replace('>', f' class="{css_class}">'))
        return value
    

    【讨论】:

      【解决方案2】:

      另一种方法是在字段上使用as_widget 方法来更改它——比正则表达式方法更简单、更安全,并且不需要任何额外的依赖项。

      定义一个custom template filter

      @register.filter
      def add_class(field, class_name):
          return field.as_widget(attrs={
              "class": " ".join((field.css_classes(), class_name))
          })
      

      在你的模板中:

      {{ form.first_name|add_class:"span-4" }}
      

      也可以使用as_widget添加其他属性,如placeholder

      【讨论】:

      • 喜欢这个优雅的解决方案,而且我现在学会了如何使用模板标签。谢谢!
      【解决方案3】:

      关于 lazerscience 解决方案的另一个注意事项:如果将其应用于没有类属性的

      <select name="state" id="id_state" class="class1 class2">
          <option value="AL" class="class1 class2">Alabama</option class="class1 class2">
          <option value="AK" class="class1 class2">Alaska</option class="class1 class2">
          <option value="AZ" class="class1 class2">Arizona</option class="class1 class2">
      </select class="class1 class2">
      

      我很确定浏览器会废弃那些无关的类定义,但是当您只需要一个时,这就是大量的字符串替换。一个简单的补救措施:

      return mark_safe(string.replace('>', ' class="%s">' % css_class, 1))
      

      最后一个参数 (1) 将确保只有“>”的第一个实例将替换为“class="...">,这在逻辑上对于任何表单元素都是正确的。

      【讨论】:

      • 嗨,谢谢你的灵感,我猜我还没用过select
      【解决方案4】:

      我还在学习 Django,但你不能这样做吗 -

      from django import forms
      
      class SomeForm(forms.Form):
          f = forms.CharField(label='x',widget=forms.TextInput(attrs={'class':'name'}))
      

      我想没有必要在模板级别执行此操作(或使用过滤器),除非您有一些我不理解的要求。

      【讨论】:

      • 将样式(css)与功能(表单)分开会更简洁。例如,如何使用此方法有条件地将类添加到模板中的表单字段?此外,您如何以不同的方式显示此表单,而不会复制表单,例如移动友好的表单和不那么移动友好的表单?表单提供的验证不会改变,但它的视图会改变。
      • 在表单级别应用的 CSS 类不会影响不同的显示。表单类在任何设备上都应该保持不变,并且您应该在需要时具有由设备专门化的特定 css 文件配置。
      • 这是正确的答案,在大多数情况下。无需乱用正则表达式!也可以提一下 ModelForm 的案例:class Meta: widgets={'f': forms.TextInput(attrs={'class': 'name'})}
      【解决方案5】:

      关于如何使用 Lazerscience 非常方便的解决方案的一些额外说明。以下是文件在依赖项导入时的外观:

      import re
      from django.utils.safestring import mark_safe
      from django import template
      register = template.Library()
      
      class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
      @register.filter
      def add_class(value, css_class):
          string = unicode(value)
          match = class_re.search(string)
          if match:
              m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                                                          css_class, css_class), 
                                                          match.group(1))
              print match.group(1)
              if not m:
                  return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
                                                string))
          else:
              return mark_safe(string.replace('>', ' class="%s">' % css_class))
          return value
      

      我将它粘贴到一个名为 add_class.py 的文件中。目录结构为: mydjangoproject > general_tools_app > templatetags > add_class.py

      general_tools_app 是一个应用程序,它收集了我添加到新 django 项目中的有用功能。

      (general_tools_app 和 templatetags 目录都有一个空的__init__.py 文件,以便正确注册)

      在 settings.py 中,我的 INSTALLED_APPS 元组包含条目“mydjangoproject.general_tools_app”。

      要在模板中使用过滤器,我在文件顶部添加了{% load add_class %} 行。如果我想将“删除”类添加到字段中,我会这样做

      {{ myfield|add_class:'delete' }}
      

      【讨论】:

      • 我发现class_re 的定义有点过于贪婪,最终在某些字段中,该类被输入到type 属性而不是class。我的修改版:class_re = re.compile(r'(?&lt;=class=["\'])([^"\']*)(["\'])')
      【解决方案6】:

      你只需要安装 Django widget_tweaks

      pip install django-widget-tweaks
      

      在你可以在你的模板上做类似的事情之后:

      {{ form.search_query|attr:"type:search" }}
      

      --

      阅读所有相关信息here

      【讨论】:

      • 我正在寻找如何将类添加到labels,我记得手动添加它们很简单:&lt;label class="the-class" for="{{ field.auto_id }}"&gt;{{ field.label }}&lt;/label&gt;
      【解决方案7】:

      为了解决这个问题,我制作了自己的模板过滤器,您可以将其应用于任何标签,而不仅仅是输入元素!

      class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
      @register.filter
      def add_class(value, css_class):
          string = unicode(value)
          match = class_re.search(string)
          if match:
              m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                                                          css_class, css_class), 
                                                          match.group(1))
              print match.group(1)
              if not m:
                  return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
                                                string))
          else:
              return mark_safe(string.replace('>', ' class="%s">' % css_class))
          return value
      

      【讨论】:

      • 做得很好。为了使它适用于以 '/>' 结尾的字段,我使用了 return mark_safe(string.replace(' ', ' class="%s" ' % css_class)) - 使用空格而不是 '>' 以便它会找到第一个空格并在其余部分之前注入属性。
      • 正则表达式匹配贪婪,但应该匹配惰性。我已将上面的代码更改为class_re = re.compile(r'(?&lt;=class=["\'])(.*?)(?=["\'])')。否则它会匹配到最后一个 " 字符而不是类的结尾。
      【解决方案8】:

      您需要明确指定小部件并使用attrs keyword argument 添加类。据我所知,没有其他方法。

      但是,如果这太麻烦,您仍然可以将字段包装在另一个元素中,例如 div 或 span 并为其添加一个类。然后相应地修改你的 CSS。

      【讨论】:

      • 正如我已经提到的,我想在模板中这样做,因为表单可以呈现各种外观!
      • 为了优化结果,您应该考虑阅读有关响应式布局的信息。您的模板和类应该保持不变,所有的魔法都保留在 css 上。
      猜你喜欢
      • 2011-12-30
      • 2021-03-05
      • 2019-02-23
      • 2021-12-15
      • 2016-12-04
      • 2020-02-05
      • 2017-05-10
      • 2015-11-27
      • 2016-12-06
      相关资源
      最近更新 更多