一、模板验证
1、模板语言
当我们在写网站应用的时候,需要向前端页面传递数据,这些数据是如何在前端页面上显示的呢?这就需要我们使用模板,我们把模板文件和我们的数据进行渲染后生成一个新的html文件,把这个文件的内容返回给前端,就可以展示数据了,我们首先来访问一个前端的页面。
首先,我们先创建一个模板文件template.html,所有的模板文件都应该保存在工程的template目录下:
然后,我们添加一个views函数和一条URL:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
def template(request,*args): if request.method == "GET": # 将模板template.html返回 return render(request,"template.html")
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from django.conf.urls import url from admin import views urlpatterns = [ url(r'^index/',views.index.as_view(),name="test1"), url(r'^template',views.template), ]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>This is a template page!</h1> </body> </html>
现在,我们访问以下/admin/template/这个url,可以看到如下页面:
现在,我们的模板文件已经可以访问了,接下来我们要把我们的数据和模板文件渲染后显示在前端页面上,首先来看下模板语言的语法和流程控制,我们在views函数中的return部分加入我们要传递的参数:
def template(request,*args): if request.method == "GET": # 将模板template.html返回 data = ["张三","李四","王五","赵六"] age = {"张三":24,"李四":25,"王五":31,"赵六":22} return render(request,"template.html",{"name":data,"title":"这是姓名表","age":age})
接下来我们来看模板文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>取单个值</h3> {{ title }} <h3>遍历列表</h3> {% for i in name %} <p>{{ i }}</p> {% endfor %} <h3>根据列表索引取单个值</h3> {{ name.2 }} <h3>判断</h3> {% if name.2 == "王五" %} <p>{{ name.2 }}</p> {% endif %} <h3>遍历字典的key</h3> {% for foo in age.keys %} <ul> <li>{{ foo }}</li> </ul> {% endfor %} <h3>遍历字典的value</h3> {% for j in age.values %} <ul> <li>{{ j }}</li> </ul> {% endfor %} <h3>遍历字典的键值对</h3> {% for k,v in age.items %} <ul> <li>{{ k }} -- {{ v }}</li> </ul> {% endfor %} </body> </html>
这时我们再来访问以下刚才的URL:
总结一下:
1)views函数,向前端发送数据时使用字典的形式,前端根据字典的key来取值。
2)前端取单个值 {{ 键 }},注意是两个“{{”再加一个空格,空格很重要,否则语法错误。
3)for循环:{% for i in xxx %} 。。。。。 {% endfor %},对于列表类型的数据,xxx表示后端传递字典中的key,对于字典,还可以通过xxx.keys、xxx.values、xxx.items这三个方法来遍历键、值、键值对,在遍历键值对时,需要两个变量
4)当需要取列表中的某个值的时候可以使用key.index,即使.和索引值来取值
5)判断:{% if xxx %} {% else %} {% endif %},注意空格
2、模板继承和模板插件
a、模板继承
了解完模板语言的基本语法后,我们已经可以实现向前端传递数据的需求,但是,接着思考一个问题,一个网站,一般导航栏都是一样的,如果我们每写一个页面,就把导航栏重写一遍,先不说复制粘贴是否麻烦,如果导航栏需要更改……我的天呐,所有的页面都改一遍,这尼玛……
为了避免上述的尴尬,我们需要使用模板继承的方式,定义一个母版html文件,其他页面继承该html,这样所有页面上母版中定义的内容都是相同的,所有继承母版的子版都把自己作为母版的一部分套入母版,需要修改的时候直接修改母版,所有继承母版的页面就都一起改了,接下来,我们创建三个html,master.html、web1.html、web2.html,分别用作母版、页面一、页面二,其中web1.html和web2.html都继承master.html。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .head { width: 100%; height: 200px; background: orange; } </style> </head> <body> <div class="head"> <h1>我是一个导航栏!</h1> <a href="/admin/web1/">去页面一</a> <a href="/admin/web2/">去页面二</a> </div> {% block content %} {% endblock %} </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
{% extends "master.html" %} {% block content %} <ul> <li>这是页面一</li> <li>这是页面一</li> <li>这是页面一</li> <li>这是页面一</li> </ul> {% endblock %}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
{% extends "master.html" %} {% block content %} <p> <a href="http://www.baidu.com">这是页面二</a> </p> {% endblock %}
接下来,我们定义两个views函数和url,然后访问一下看看效果:
web1页面如下:
web2页面如下:
我们可以看到,web1和web2中的导航条部分都是一样的了,但是还有个问题,如果我们需要给web1和web2设置不同的title,或者加载不同的css、js文件时该怎么办呢?也有办法,使用block就可以添加了,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <style> .head { width: 100%; height: 200px; background: orange; } </style> {% block css %} {% endblock %} </head> <body> <div class="head"> <h1>我是一个导航栏!</h1> <a href="/admin/web1/">去页面一</a> <a href="/admin/web2/">去页面二</a> </div> {% block content %} {% endblock %} </body> {% block js %} {% endblock %} </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
{% extends "master.html" %} {% block css %} <style> body { background: red; } </style> {% endblock %} {% block content %} <ul> <li>这是页面一</li> <li>这是页面一</li> <li>这是页面一</li> <li>这是页面一</li> </ul> {% endblock %}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
{% extends "master.html" %} {% block content %} <p> <a href="http://www.baidu.com">这是页面二</a> </p> {% endblock %} {% block js %} <script> alert("这是web2"); </script> {% endblock %}
在模板渲染时,Django会帮我们把母版中block的部分替换为子版中对应名称的block。
总结一下:
1)母版中使用{% block name %} {% endblock %}来定义要加载进子版内容的位置
2)子版继承母版时,需要使用{% extends "模板文件名" %},一个文件中只能有一个extends继承
3)母版中可以通过{% block 块名 %}{% endblock %}来设置块,子版中可以通过同样的block名称来将子版中的代码引入母版对应的块中
b、模板插件
当我们希望在同一个网页中加载更多的其他的网页的时候,比如一些小功能模块等,此时用extends就不太方便了,这个时候我们依然有解决的办法,那就是使用模板插件,用include将你要的小功能html加入你的文件中。我们来看代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <style> .head { width: 100%; height: 200px; background: orange; } </style> {% block css %} {% endblock %} </head> <body> <div class="head"> <h1>我是一个导航栏!</h1> <a href="/admin/web1/">去页面一</a> <a href="/admin/web2/">去页面二</a> </div> {% block content %} {% endblock %} </body> {% block js %} {% endblock %} </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
{% extends "master.html" %} {% block css %} <style> body { background: red; } </style> {% endblock %} {% block content %} <ul> <li>这是页面一</li> <li>这是页面一</li> <li>这是页面一</li> <li>这是页面一</li> </ul> {% include "insert.html" %} {% include "insert.html" %} {% include "insert.html" %} {% endblock %}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
{% extends "master.html" %} {% block content %} <p> <a href="http://www.baidu.com">这是页面二</a> {% include "insert.html" %} </p> {% endblock %} {% block js %} <script> alert("这是web2"); </script> {% endblock %}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .tool { width: 300px; height: 300px; border: solid 1px; } </style> </head> <body> <div class="tool"> <p>这是一个小插件</p> </div> </body> </html>
我们在web1和web2这两个页面中都插入了insert.html这个网页,这个页面就是一个小插件。
web1页面:
web2页面:
总结一下:
1)使用{% include "插件html" %},可以在页面中将另一个页面作为小插件加入页面中
2)一个页面中可以使用多个include来包含多个插件
3)模板语言一样可以在插件中使用,Django会将所有的页面一起渲染后再显示出来
3、分页
我们在浏览网页的时候,如果页面太长,我们经常能看到页面上会出现翻页的按钮,那这个分页的功能是如何实现的呢,学完模板语言的我们就可以自己来实现一个分页的功能了,分页功能原理很简单,主要需要我们理清逻辑,我们来看代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
from django.utils.safestring import mark_safe LIST = [] for i in range(184): LIST.append(i) def page(request): # 用户点击的当前页面页码 current_page = request.GET.get('p',1) current_page = int(current_page) # 所有数据的长度,决定我们需要多少分页 data_len = len(LIST) # 每个页面上显示多少条数据 per_page_count = 10 # 用于将数据切片的起始位置,根据当前页的页码生成切片的起始位置 start = (current_page - 1) * per_page_count # 用于将数据切片的终止位置,根据当前页面页码生成切片的终止位置 end = current_page * per_page_count # 根据总数据长度和每页显示的数据条目相除商和余数,余数不为0时,总页码加一 page_count,last = divmod(data_len,per_page_count) if last: page_count += 1 # 对数据切片 li = LIST[start:end] # 声明变量用于存放生成的翻页按钮的字符串 link_list = [] # 页面上要显示的翻页按钮的数量,最好写成奇数,页面生成的页码才对称 display_page_num = 13 # 如果当前请求的页面小于等于页面显示页码数的中位数,那么页码起始位置为1,结束位置为显示页码数加一 if current_page <= (display_page_num + 1)/2: page_start = 1 page_end = display_page_num + 1 else: # 如果当前页码位于总页码后几项,那么起始位置就是总页码减去显示页码数量,结束页码就是总页码加一 if current_page > page_count - int((display_page_num + 1)/2): page_end = page_count + 1 page_start = page_count - display_page_num else: # 否则,终止页码就是当前页码加上显示页码加一后的一半 page_end = current_page + int((display_page_num + 1)/2) # 否则,起始页码就是当前页码减去显示页码减一后的一半 page_start = current_page - int((display_page_num - 1)/2) # 将起始页码和终止页码加入range()生成页码字符串 for item in range(page_start,page_end): # 如果当前页码被选中,就为当前页码添加一个css样式active,用于标识当前的页码 if item == current_page: tmp = '<a class="page active" href="/admin/page_list/?p=%s">%s</a>' %(item,item) else: tmp='<a class="page" href="/admin/page_list/?p=%s">%s</a>' %(item,item) # 把所有的页码字符串加入页码字符串列表 link_list.append(tmp) # 成成页码html字符串 link_str = "".join(link_list) # 声明该字符串为安全字符串,页面上显示为html代码 link_str = mark_safe(link_str) return render(request,"page.html",{"li":li,"page":link_str})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .page{ display: inline-block; text-align: center; width: 30px; height: 30px; line-height: 30px; background: orange; margin: 5px; padding: 5px; color: white; } .active { background: brown; } </style> </head> <body> <ul> {% for item in li %} <li>{{ item }}</li> {% endfor %} </ul> </body> </html>
页面效果如下,我们可以看到,当当前页面小于7时,总共显示13个翻页的按钮
关于xss攻击:当我们在页面上允许用户评论或者提交数据时,如果用户提交一段js代码,那页面渲染时这段代码是不是就会执行呢?很明显,这是不可以的,这种攻击方式就是xss攻击,为了防止用户提交的代码被执行,我们默认认为用户或者后台生成的代码都是不安全的,都会被当做字符串来处理,比如我们分页代码中生成的那些a标签,默认认为其就是一段字符串,如果我们想让这段字符串变成html代码被执行,那么我们就需要做安全声明,安全声明的方式有两种,在前端html模板中可以实现,比如上述代码中,我们在page.html中使用如下代码既可以做安全声明:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .page{ display: inline-block; text-align: center; width: 30px; height: 30px; line-height: 30px; background: orange; margin: 5px; padding: 5px; color: white; } .active { background: brown; } </style> </head> <body> {#前端安全声明,通过管道符和safe关键字来声明#} {{ page|safe }} </body> </html>
同样,我们还可以在后端将我们要执行的html字符串声明成安全的字符串,上述代码中我们用到的mark_safe()方法就是来实现这个功能的,在使用这个方法之前我们需要先导入这个方法,导入方法为:from django.utils.safestring import mark_safe
二、form表单验证
我们在需要用户提交数据时,需要对用户的输入和提交的数据做一些验证,比如是否为空,数据格式是否正确,数据长度是否合法等等,当用户输入不合法的时候我们在前端页面上需要给用户显示错误提示信息,还需要保留用户已经填写的数据供用户修改,这些功能的实现方法有多种,但是如果我们都自己写的话是很麻烦的事情,这时我们就可以用Django给我们提供的form表单验证方式来很方便的实现这些功能。除了验证表单数据外,form还可以帮我们生成html。
form表单验证的功能:
1)用户数据验证并生成错误提示信息
2)生成html
3)保留用户输入信息
4)初始化页面显示内容
1、用户数据验证
使用form表单验证时,大致步骤如下:
a、导入forms模块,创建form类,定义字段
b、views函数调用,生成form对象
c、将该对象传递给前端,前端从其中获取错误提示
d、调用form对象的is_valid()方法获取用户数据验证结果
e、验证通过后获取正确数据
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
# 导入forms模块 from django import forms # 生成form类 class FM(forms.Form): # 定义字段user,该user字段对应前端input标签的name字段名,该字段为CharField字段,表示字符串字段 user = forms.CharField() pwd = forms.CharField() # 该字段为EmailField字段,表示该字段中要填入email格式 email = forms.EmailField() def fm(request): if request.method == "GET": obj = FM() return render(request,"fm.html",{"obj":obj}) elif request.method == "POST": # 生成form对象 obj = FM(request.POST) # 判断用户输入的值是否合法,数据合法则res为True,数据非法则res为False res = obj.is_valid() print(res) if res: # cleaned_data表示用户输入的合法的数据 print(obj.cleaned_data) else: # errors表示错误信息 print(obj.errors) # errors的as_json()方法会以json的形式返回错误信息 print(obj.errors.as_json()) return render(request,"fm.html",{"obj":obj})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/admin/fm/" method="POST"> <p><input type="text" name="user"> {{ obj.errors.user.0 }}</p> <p><input type="password" name="pwd"> {{ obj.errors.pwd.0 }}</p> <p><input type="text" name="email"> {{ obj.errors.email.0 }}</p> <p><input type="submit" value="提交"></p> </form> </body> </html>
我们可以看到,在页面上对用户输入的内容已经有了验证:
但是这个验证信息是英文,我们是否可以自定义错误提示信息呢?当然可以,我们只需要改一下form表单类中字段就可以了,看代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
class FM(forms.Form): # 定义字段user,该user字段对应前端input标签的name字段名,该字段为CharField字段,表示字符串字段 user = forms.CharField(error_messages={"required":"用户名不能为空"}) pwd = forms.CharField(error_messages={"required":"密码不能为空"}) # 该字段为EmailField字段,表示该字段中要填入email格式 email = forms.EmailField(error_messages={"required":"邮箱地址不能为空","invalid":"邮箱格式不正确"})
此时我们再来访问一下这个url来看下效果:
此时,错误提示的信息就是我们自定义的信息了。但是我们可以看到,此时,当用户输入一个错误的数据提交后,虽然有错误提示了,但是用户原来输入的数据却没有了,显然,这是不合适的,我们应该保留用户的输入,此时,我们就可以使用forms表单验证第二个牛逼的功能,生成html来实现
2、生成html
利用forms生成html的功能,可以直接把form对象传递给前端,在前端生成html,此时就可以在显示错误提示信息的同时保留用户输入的数据了。来看代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/admin/fm/" method="POST"> <p>{{ obj.user }} {{ obj.errors.user.0 }}</p> <p>{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p> <p>{{ obj.email }} {{ obj.errors.email.0 }}</p> <p><input type="submit" value="提交"></p> </form> </body> </html>
此时我们可以看到,当用户提交错误的数据格式时,不仅有错误提示,而且之前用户输入的数据依然得到了保存。
其实使用forms生成html,还有更牛逼的功能,我们上述代码中,用p标签将所有的input标签包裹在了其中,其实我们可以很方便的在html文件中调用form对象的as_p方法来直接生成这样的html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/admin/fm/" method="post"> {{ obj.as_p }} <p><input type="submit" value="提交"></p> </form> </body> </html>
除此之外,我们还可以使用as_ul生成列表型表单,使用as_table生成表格型表单,但是需要注意的是,使用as_table方法时,我们应该将其放在<table></table>标签之中:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/admin/fm/" method="post"> {{ obj.as_ul }} <p><input type="submit" value="提交"></p> </form> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/admin/fm/" method="post"> <table> {{ obj.as_table }} </table> <p><input type="submit" value="提交"></p> </form> </body> </html>
上述代码在页面上显示效果分别如下:
我们可以看到,前端模板中我们只写了很少的代码就实现了我们的功能,但是这个方法在我们需要自定义一些东西时就不太方便了,所以还是推荐使用前面那种用p标签包裹的方式来实现,方便我们做一些样式上的调整。
3、插件
上面我们已经看到,我们可以直接在前端使用forms对象来生成HTML代码,但是,我们生成的只有<input>标签,那如果我们想要生成一些别的标签呢?比如搞个下拉列表什么的呢?这些其实也是可以通过forms来生成的,只不过,这就要使用到插件的功能了,比如,我们把上面的代码中User字段变成一个多行文本框:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
# 导入forms模块 from django import forms # 导入widgets模块 from django.forms import widgets # 生成forms类 class FM(forms.Form): # 定义字段user,该user字段对应前端input标签的name字段名,该字段为CharField字段,表示字符串字段 user = forms.CharField( error_messages={"required":"用户名不能为空"}, # 定义字段时使用widget参数来设置插件 widget=widgets.Textarea() ) pwd = forms.CharField(error_messages={"required":"密码不能为空"}) # 该字段为EmailField字段,表示该字段中要填入email格式 email = forms.EmailField(error_messages={"required":"邮箱地址不能为空","invalid":"邮箱格式不正确"})
上述代码中widgets模块就是插件模块,使用前需要我们先导入,接下来我们看下前端的显示效果:
我们可以看到,我们的User字段已经变成了一个多行文本框。那么问题又来了,如果我们想要给生成的html定制样式或者属性,那该怎么办呢?其实很简单,改一行代码就可以实现上述需求了:
widget=widgets.Textarea(attrs={"class":"c1","placeholder":"请输入一段话"})
此时我们再来看一下前端的样式:
此时我们看到,我们给User这个字段加了一个class叫c3,还加了一个placeholder的属性,这样通过插件中的attrs参数,就可以设置生成的html代码的各项属性值了。
至此,我们总结一下,forms生成html的方法和步骤:
1)从django中导入forms模块,从forms模块中导入widgets模块,定义forms类,这个类继承forms.Form父类;
2)选择要创建的字段
3)设置字段的属性
4)选择合适的插件
5)设置插件的属性
froms中可用的字段如下:
Field required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀 CharField(Field) max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度 BaseTemporalField(Field) input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正则表达式 max_length=None, 最大长度 min_length=None, 最小长度 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允许空文件 ImageField(FileField) ... 注:需要PIL模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默认select插件 label=None, Label内容 initial=None, 初始值 help_text='', 帮助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查询数据库中的数据 empty_label="---------", # 默认空显示内容 to_field_name=None, # HTML中value的值对应的字段 limit_choices_to=None # ModelForm中对queryset二次筛选 ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 对选中的每一个值进行一次转换 empty_value= '' 空值的默认值 ComboField(Field) fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field) PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符) ... UUIDField(CharField) uuid类型 ...
Django中可用的插件如下:
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget