使用Form生成html标签的时候,虽然提供了widget的方法可以自定义标签的要是,但是只能给生成的input标签添加样式,对于生成的label标签无法添加样式。
而很多场景下需要为label和input都添加class以实现自定义样式。
测试环境
创建一个Form,通过Form帮我们生成HTML:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
path( 'email/' , views.email),
from django.forms import Form
from django.forms import fields
from django.forms import widgets
class UserEmail(Form):
username = fields.CharField()
password = fields.CharField(
widget = widgets.PasswordInput(attrs = { 'class' : 'c1' })
)
email = fields.EmailField(
widget = widgets.EmailInput(attrs = { 'class' : 'c1' })
)
def email(request):
obj = forms.UserEmail()
print (obj[ 'email' ].label_tag(attrs = { 'class' : 'c1' }))
return render(request, 'demo/email.html' , { 'obj' : obj})
|
在html中,直接使用Form帮我生成的表单:
?
1
2
3
4
5
|
<body>
{{ obj.as_p }}
{{ obj.email.label_tag }}
{{ obj.email }}
< / body>
|
这里可以看到,input标签里都是有class属性的,但是lable标签里没有,并且Form组件里貌似也没有提供为label标签增加自定义属性的方式。
通过模板语言的自定义函数实现
上面的views里的 print(obj['email'].label_tag(attrs={'class': 'c1'})) ,从输出看,django提供的生成label标签的方法是支持attrs参数实现自定义属性的,问题是在前端使用模板语言的时候只能这样 {{ obj.email.label_tag }} 无法传入参数。这里就自定义个模板语言的函数来解决这个问题。
自定义函数
要自定义函数,按照下面的步骤操作:
在APP下,创建templatetags目录,目录名字很重要不能错。
创建任意 .py 文件,这里文件名随意,比如:myfun.py。
文件里创建一个template.Library()对象,名字是register。这里的对象名字必须是register。
然后写自己的函数,但是都用@register.simple_tag这个装饰器装饰好:
自定义的函数如下:
?
1
2
3
4
5
6
7
|
from django import template
register = template.Library()
@register . filter (is_safe = True )
def label_with_classes(value, arg):
return value.label_tag(attrs = { 'class' : arg})
|
然后在页面中使用自定义的函数:
?
1
2
3
4
5
6
7
|
<body>
{{ obj.as_p }}
{{ obj.email.label_tag }}
{{ obj.email }}
{ % load myfun % }
{{ obj.email|label_with_classes: 'c1 c2' }}
< / body>
|
注意,上面的自定义函数引用的时候参数和参数之间一定不能有空格。
这里还有一个好处,把添加前端样式的代码放到了前端的html里实现了。
为input标签也写一个自定义函数
django默认的方法是在Form里,通过widgets小部件添加attrs参数来实现标签的自定义样式。这是在放在后端实现的。上面已经实现了前端的自定义样式,这里找了到生成input标签的方法,就是as_widget()。
照着样子再写一个子定义函数:
?
1
2
3
4
5
6
7
8
9
10
11
|
from django import template
register = template.Library()
@register . filter ()
def label_with_classes(value, arg):
return value.label_tag(attrs = { 'class' : arg})
@register . filter ()
def widget_with_classes(value, arg):
return value.as_widget(attrs = { 'class' : arg})
|
最后,上面搞得难么麻烦,主要是为了可以前端一个for循环,就能把表单按自定义的样式显示出来:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<body>
<link rel = "stylesheet" href = "https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel = "external nofollow"
integrity = "sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin = "anonymous" >
{ % load myfun % }
<form class = "form-horizontal" >
{ % for item in obj % }
<div class = "form-group" >
{{ item|label_with_classes: 'col-sm-2 control-label' }}
<div class = "col-sm-10" >
{{ item|widget_with_classes: 'form-control' }}
< / div>
< / div>
{ % endfor % }
< / form>
< / body>
|
补充知识:Django Forms组件 的参数配置案例 input样式, 渲染的标签加class 错误信息提示
Forms渲染出标签类型
密码型、文本型、邮箱型框
?
1
2
3
4
5
6
7
8
9
|
from django.forms import widgets
class UserForm(forms.Form):
name = forms.CharField(min_length = 4 , label = '姓名:' ,widget = widgets.TextInput())
pwd = forms.CharField(min_length = 4 , label = '密码:' , widget = widgets.PasswordInput())
|
渲染时添加属性 class=''(便于bootstrap)
?
1
2
3
4
5
6
7
8
9
10
11
12
|
from django.forms import widgets
class UserForm(forms.Form):
name = forms.CharField(widget = widgets.TextInput(attrs = { 'class' : 'form-control' }))
pwd = forms.CharField(widget = widgets.PasswordInput(
attrs = { 'class' : 'form-control' }
))
|
渲染自定义错误提示
视图
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
from django.forms import widgets
class UserForm(forms.Form):
name = forms.CharField(min_length = 4 , label = '姓名:' ,
error_messages = {
'title' : { 'required' : '不能为空哦亲亲' },
'price' : { 'invalid' : '格式错误(提示方法)' },
})
pwd = forms.CharField(min_length = 4 , label = '密码:' ,
error_messages = {
'title' : { 'required' : '不能为空哦亲亲' },
'price' : { 'invalid' : '格式错误(提示方法)' },
})
|
HTML展示错误信息
?
1
2
3
4
5
6
7
8
9
10
11
12
|
< form action = "" method = "post" novalidate = "novalidate" >
{% csrf_token %}
{% for field in form %}
< p >
{{ field.label }}{{ field }} < span >{{ field.errors.0 }}</ span >
</ p >
{% endfor %}
< p >< input type = "submit" value = "提交" ></ p >
</ form >
|
|