Django表单中的CSS样式


150

我想样式如下:

forms.py:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

contact_form.html:

<form action="" method="post">
  <table>
    {{ form.as_table }}
  </table>
  <input type="submit" value="Submit">
</form>

例如,如何设置一个IDsubjectemailmessage以提供外部样式表到?

Answers:


192

摘自我的答案: 如何在Django中使用<div class ='field_type'>标记表单字段

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

要么

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myfield'].widget.attrs.update({'class' : 'myfieldclass'})

要么

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'myfield': forms.TextInput(attrs={'class': 'myfieldclass'}),
        }

---编辑---
以上是对完成所要求内容的原始问题的代码进行的最简单的更改。如果您在其他地方重复使用表格,还可以避免重复。如果您使用Django的as_table / as_ul / as_p表单方法,则您的类或其他属性将正常工作。如果您需要完全控制以完全自定义渲染,则需要明确记录在案

-编辑2 ---
添加了更新的方法来为ModelForm指定小部件和属性。


27
尽管不建议将演示文稿与业务逻辑混合使用。
Torsten Engelbrecht

8
这个演讲怎么样?您正在为元素提供一个类,它只是一个标识符或分类。您仍然必须定义其他地方的功能
shadfc 2011年

9
是的,没有。按照惯例,第一个CSS类用于样式设置,如果您需要唯一的标识符,则最好使用id。其次,通常是模板方面的职责来做到这一点,特别是如果您要通过前端方法(js,css)访问此类。我不是说你的答案是错误的。在我看来,这只是不好的做法(尤其是在与前端和后端开发人员组成的团队中工作时)。
Torsten Engelbrecht

6
这看起来很荒谬,只是要添加一个类,您需要这么多的代码?在这些区域中硬编码HTML / CSS似乎更容易(尤其是对于CSS繁多的网站)。
David542

9
疯了的django使得这太尴尬了!
布莱斯2012年

103

可以使用自定义模板过滤器来完成。考虑以这种方式呈现表单:

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjectBoundField具有该as_widget()方法的实例。

您可以addclassmy_app / templatetags / myfilters.py中创建自定义过滤器:

from django import template

register = template.Library()

@register.filter(name='addclass')
def addclass(value, arg):
    return value.as_widget(attrs={'class': arg})

然后应用您的过滤器:

{% load myfilters %}

<form action="/contact/" method="post">
  {{ form.non_field_errors }}
  <div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject|addclass:'MyClass' }}
    <span class="helptext">{{ form.subject.help_text }}</span>
  </div>
</form>

form.subjects然后将使用MyClassCSS类呈现。


5
这是更清洁,易于实施的解决方案之一
用户

5
这个答案应该是最高答案!!!它确实比Django提出的解决方案干净!做得好@Charlesthk
David D.

4
超级有帮助。起初对我来说并不明显,但是您也可以使用它来添加多个类:{{ form.subject|addclass:'myclass1 myclass2' }}
smg 2016年

我喜欢这样,可以将HTML类保留在HTML文件中。在处理样式时,我会在样式表和结构(而不​​是模型和/或表单)之间来回切换。
凯文

29

如果您不想在表单中添加任何代码(如@shadfc的答案的注释中所述),则肯定有可能,这里有两个选择。

首先,您只需在HTML中单独引用字段,而不是一次引用整个表单:

<form action="" method="post">
    <ul class="contactList">
        <li id="subject" class="contact">{{ form.subject }}</li>
        <li id="email" class="contact">{{ form.email }}</li>
        <li id="message" class="contact">{{ form.message }}</li>
    </ul>
    <input type="submit" value="Submit">
</form>

(请注意,我也将其更改为未排序的列表。)

其次,在文档中注意将表单输出为HTML,Django:

通过在字段名称前添加“ id_”来生成字段ID。默认情况下,输出中包括id属性和标签。

您所有的表单字段都已经具有唯一的ID。因此,您可以在CSS文件中引用id_subject来设置主题字段的样式。我应该注意,这是您采用默认 HTML 时表单的行为方式,默认 HTML仅需要打印表单,而不是单个字段:

<ul class="contactList">
    {{ form }}  # Will auto-generate HTML with id_subject, id_email, email_message 
    {{ form.as_ul }} # might also work, haven't tested
</ul>

输出表格时,其他选项请参见上一个链接(您可以制作表格等)。

注意-我意识到这与向每个元素中添加不同(如果您向Form中添加了一个字段,则还需要更新CSS)-但是通过id引用所有字段很容易在您的CSS中是这样的:

#id_subject, #id_email, #email_message 
{color: red;}

我尝试了您的第二个解决方案,但没有成功。我为id_email创建了类,但未产生任何结果。
几乎是初学者

@almostabeginner我可以建议进行调试的一件事-在浏览器中看到该页面后,使用View Page Source(通常通过右键单击),然后查看Django生成的实际完整页面。查看字段是否存在,以及所需的ID标识符。同样,大多数浏览器(可能通过安装插件)都可以运行调试器,该调试器向您显示应用于页面的css,这也有助于了解发生的情况。
约翰·C

@almostabeginner还请注意,我添加了一些示例代码。如果仅凭文本不清楚,则必须引用表单本身,而不是单个字段,此时,表单将自动生成包含id的 HTML ,如所述。希望有帮助。
约翰·C

1
感谢您的帮助,问题根本不是我的CSS,问题与缓存有关。因此我的旧CSS已存储,因此不会显示任何更改。我刚刚从chrome中清除了缓存,所有更新都开始显示。
几乎是初学者

15

根据博客文章,您可以使用自定义模板过滤器将CSS类添加到字段中。

from django import template
register = template.Library()

@register.filter(name='addcss')
def addcss(field, css):
    return field.as_widget(attrs={"class":css})

将其放在应用程序的templatetags /文件夹中,您现在可以

{{field|addcss:"form-control"}}

2
这应该已经被接受为对此帖子的真正答案:)
mvdb

迄今为止最好的解决方案。
Mods vs Rockers'3

1
太好了,谢谢!不要忘记实际加载标签。另外,在Django 2.1中,我可以让Django找到模板的唯一方法是在settings.py中添加一个选项:'libraries':{'add_css':'app.templatetags.tag_name',}
simonbogarde



5

你可以做:

<form action="" method="post">
    <table>
        {% for field in form %}
        <tr><td>{{field}}</td></tr>
        {% endfor %}
    </table>
    <input type="submit" value="Submit">
</form>

然后,您可以将class / id添加到例如<td>标记中。您当然可以使用所需的任何其他标签。选中“使用Django表单作为示例” field,该表单中的每个表单都有哪些可用的内容({{field}}例如,仅输出输入标签,而不是标签等)。


3

一种解决方案是在页面准备好后,使用JavaScript添加所需的CSS类。例如,使用bootstrap类(为简洁起见,使用jQuery)对django表单输出进行样式设置:

<script type="text/javascript">
    $(document).ready(function() {
        $('#some_django_form_id').find("input[type='text'], select, textarea").each(function(index, element) {
            $(element).addClass("form-control");
        });
    });
</script>

这避免了将样式细节与业务逻辑相混合的麻烦。


3

像这样写你的表格:

    class MyForm(forms.Form):
         name = forms.CharField(widget=forms.TextInput(attr={'class':'name'}),label="Your Name")
         message = forms.CharField(widget=forms.Textarea(attr={'class':'message'}), label="Your Message")

在您的HTML字段中执行以下操作:

{% for field in form %}
      <div class="row">
        <label for="{{ field.name}}">{{ field.label}}</label>{{ field }}
     </div>
{% endfor %}

然后在您的CSS中编写如下内容:

.name{
      /* you already have this class so create it's style form here */
}
.message{
      /* you already have this class so create it's style form here */
}
label[for='message']{
      /* style for label */
}

希望这个答案值得一试!请注意,您必须已经编写了视图以呈现包含表单的HTML文件。


谢谢。但是如何写特定的标签文本?
gakeko betsi,

2

您可能不需要覆盖表单类' __init__,因为Django 在HTML中设置了nameid属性input。您可以拥有如下所示的CSS:

form input[name='subject'] {
    font-size: xx-large;
}

1
为此。给定“主题=表单...”,id =“ id_subject”和name =“ subject”是这些属性的Django约定。因此,您还应该能够执行#id_subject {...}
solartic,2011年

@solartic:对,谢谢。我之所以没有提及,是因为idDjango为表单集创建的字段变得毛茸茸的……
tehfink 2011年

2

真的没看到这个...

https://docs.djangoproject.com/zh-CN/1.8/ref/forms/api/#more-granular-output

更细粒度的输出

as_p(),as_ul()和as_table()方法只是懒惰的开发人员的快捷方式-它们不是显示表单对象的唯一方法。

class BoundField用于显示HTML或访问Form实例的单个字段的属性。

此对象的str()(Python 2上的unicode)方法显示此字段的HTML。

要检索单个BoundField,请使用字段名称作为键在表单上使用字典查找语法:

>>> form = ContactForm()
>>> print(form['subject'])
<input id="id_subject" type="text" name="subject" maxlength="100" />

要检索所有BoundField对象,请迭代以下形式:

>>> form = ContactForm()
>>> for boundfield in form: print(boundfield)
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="email" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

特定于字段的输出采用表单对象的auto_id设置:

>>> f = ContactForm(auto_id=False)
>>> print(f['message'])
<input type="text" name="message" />
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" />

2

有一个非常容易安装且非常适合Django的工具,可用于样式设置,并且可用于每个前端框架(如Bootstrap,Materialize,Foundation等)。它称为widget-tweaks文档:Widget Tweaks

  1. 您可以将其与Django的通用视图一起使用
  2. 或使用您自己的形式:

从Django导入表格

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

而不是使用默认值:

{{ form.as_p }} or {{ form.as_ul }}

您可以使用render_field属性以自己的方式对其进行编辑,该属性为您提供了一种类似于html的样式设置方式,例如以下示例:

template.html

{% load widget_tweaks %}

<div class="container">
   <div class="col-md-4">
      {% render_field form.subject class+="form-control myCSSclass" placeholder="Enter your subject here" %}
   </div>
   <div class="col-md-4">
      {% render_field form.email type="email" class+="myCSSclassX myCSSclass2" %}
   </div>
   <div class="col-md-4">
      {% render_field form.message class+="myCSSclass" rows="4" cols="6" placeholder=form.message.label %}
   </div>
</div>

该库使您有机会将前端与后端完全分开


1

在Django 1.10(可能更早)中,您可以按照以下步骤进行操作。

模型:

class Todo(models.Model):
    todo_name = models.CharField(max_length=200)
    todo_description = models.CharField(max_length=200, default="")
    todo_created = models.DateTimeField('date created')
    todo_completed = models.BooleanField(default=False)

    def __str__(self):
        return self.todo_name

形成:

class TodoUpdateForm(forms.ModelForm):
    class Meta:
        model = Todo
        exclude = ('todo_created','todo_completed')

模板:

<form action="" method="post">{% csrf_token %}
    {{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.todo_name.errors }}
    <label for="{{ form.name.id_for_label }}">Name:</label>
    {{ form.todo_name }}
</div>
<div class="fieldWrapper">
    {{ form.todo_description.errors }}
    <label for="{{ form.todo_description.id_for_label }}">Description</label>
    {{ form.todo_description }}
</div>
    <input type="submit" value="Update" />
</form>

0

编辑:做我建议的另一种(稍微好一点)的方法是在这里回答:Django表单输入字段样式

以上所有选项都很棒,只是以为我会扔掉这个选项,因为它是不同的。

如果要在表单上自定义样式,类等,则可以在模板中输入与表单字段匹配的html输入。例如,对于一个CharField(默认窗口小部件是TextInput),假设您想要一个看起来像引导程序的文本输入。您将执行以下操作:

<input type="text" class="form-control" name="form_field_name_here">

而且只要你把表单字段名称匹配的HTML nameattribue,(和小部件可能需要匹配输入类型为好)Django将在该场运行的所有相同的验证,当您运行validateform.is_valid()

设置标签,错误消息和帮助文本等其他样式的样式不需要太多解决方法,因为您可以根据需要执行类似的操作form.field.error.as_text并设置样式。实际字段是需要修改的字段。

我不知道这是最好的方法还是我推荐的方法,但这是一种方法,可能对某人来说是正确的。

这是有用的样式表演练,它包括SO上列出的大多数答案(例如,在小部件上使用attr和小部件调整)。 https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html


0

样式化小部件实例

如果要使一个窗口小部件实例看起来与另一个窗口小部件实例不同,则需要在实例化窗口小部件对象并将其分配给表单字段时指定其他属性(并可能在CSS文件中添加一些规则)。

https://docs.djangoproject.com/zh-CN/2.2/ref/forms/widgets/

为此,请在创建窗口小部件时使用Widget.attrs参数:

class CommentForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
    url = forms.URLField()
    comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

您还可以在表单定义中修改小部件:

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

    name.widget.attrs.update({'class': 'special'})
    comment.widget.attrs.update(size='40')

或者,如果未在表单上直接声明该字段(例如模型表单字段),则可以使用Form.fields属性:

class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class': 'special'})
        self.fields['comment'].widget.attrs.update(size='40')

然后,Django将在渲染的输出中包括额外的属性:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40" required></td></tr>
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.