from django.shortcuts import render,HttpResponse # Create your views here. from app01.models import * from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger def index(request): ''' 批量导入数据: Booklist=[] for i in range(100): Booklist.append(Book(title="book"+str(i),price=30+i*i)) Book.objects.bulk_create(Booklist) ''' ''' 分页器的使用: book_list=Book.objects.all() paginator = Paginator(book_list, 10) print("count:",paginator.count) #数据总数 print("num_pages",paginator.num_pages) #总页数 print("page_range",paginator.page_range) #页码的列表 page1=paginator.page(1) #第1页的page对象 for i in page1: #遍历第1页的全部数据对象 print(i) print(page1.object_list) #第1页的全部数据 page2=paginator.page(2) print(page2.has_next()) #是否有下一页 print(page2.next_page_number()) #下一页的页码 print(page2.has_previous()) #是否有上一页 print(page2.previous_page_number()) #上一页的页码 # 抛错 #page=paginator.page(12) # error:EmptyPage #page=paginator.page("z") # error:PageNotAnInteger ''' book_list=Book.objects.all() paginator = Paginator(book_list, 10) page = request.GET.get('page',1) currentPage=int(page) try: print(page) book_list = paginator.page(page) except PageNotAnInteger: book_list = paginator.page(1) except EmptyPage: book_list = paginator.page(paginator.num_pages) return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <h4>分页器</h4> <ul> {% for book in book_list %} <li>{{ book.title }} -----{{ book.price }}</li> {% endfor %} </ul> <ul class="pagination" id="pager"> {% if book_list.has_previous %} <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li> {% else %} <li class="previous disabled"><a href="#">上一页</a></li> {% endif %} {% for num in paginator.page_range %} {% if num == currentPage %} <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li> {% else %} <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li> {% endif %} {% endfor %} {% if book_list.has_next %} <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li> {% else %} <li class="next disabled"><a href="#">下一页</a></li> {% endif %} </ul> </div> </body> </html>
def index(request): book_list=Book.objects.all() paginator = Paginator(book_list, 15) page = request.GET.get('page',1) currentPage=int(page) # 若是页数十分多时,换另一种显示方式 if paginator.num_pages>30: if currentPage-5<1: pageRange=range(1,11) elif currentPage+5>paginator.num_pages: pageRange=range(currentPage-5,paginator.num_pages+1) else: pageRange=range(currentPage-5,currentPage+5) else: pageRange=paginator.page_range try: print(page) book_list = paginator.page(page) except PageNotAnInteger: book_list = paginator.page(1) except EmptyPage: book_list = paginator.page(paginator.num_pages) return render(request,"index.html",locals())
""" 分页组件使用示例: obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info) page_user_list = USER_LIST[obj.start:obj.end] page_html = obj.page_html() return render(request,'index.html',{'users':page_user_list,'page_html':page_html}) """ class Pagination(object): def __init__(self,current_page,all_count,base_url,per_page_num=2,pager_count=11): """ 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :param base_url: 分页中显示的URL前缀 :param pager_count: 最多显示的页码个数 """ try: current_page = int(current_page) except Exception as e: current_page = 1 if current_page <1: current_page = 1 self.current_page = current_page self.all_count = all_count self.per_page_num = per_page_num self.base_url = base_url # 总页码 all_pager, tmp = divmod(all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count self.pager_count_half = int((pager_count - 1) / 2) @property def start(self): return (self.current_page - 1) * self.per_page_num @property def end(self): return self.current_page * self.per_page_num def page_html(self): # 若是总页码 < 11个: if self.all_pager <= self.pager_count: pager_start = 1 pager_end = self.all_pager + 1 # 总页码 > 11 else: # 当前页若是<=页面上最多显示11/2个页码 if self.current_page <= self.pager_count_half: pager_start = 1 pager_end = self.pager_count + 1 # 当前页大于5 else: # 页码翻到最后 if (self.current_page + self.pager_count_half) > self.all_pager: pager_end = self.all_pager + 1 pager_start = self.all_pager - self.pager_count + 1 else: pager_start = self.current_page - self.pager_count_half pager_end = self.current_page + self.pager_count_half + 1 page_html_list = [] first_page = '<li><a href="%s?page=%s">首页</a></li>' % (self.base_url,1,) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: prev_page = '<li><a href="%s?page=%s">上一页</a></li>' % (self.base_url,self.current_page - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): if i == self.current_page: temp = '<li class="active"><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,) else: temp = '<li><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一页</a></li>' else: next_page = '<li><a href="%s?page=%s">下一页</a></li>' % (self.base_url,self.current_page + 1,) page_html_list.append(next_page) last_page = '<li><a href="%s?page=%s">尾页</a></li>' % (self.base_url,self.all_pager,) page_html_list.append(last_page) return ''.join(page_html_list)
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,而且在全局上改变django的输入与输出。由于改变的是全局,因此须要谨慎实用,用很差会影响到性能。javascript
Django的中间件的定义:css
1
|
Middleware
is
a framework of hooks into Django’s request
/
response processing. <br>It’s a light, low
-
level “plugin” system
for
globally altering Django’s
input
or
output.
|
若是你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些均可以经过中间件来实现。html
可能你还想在view执行以前作一些操做,这种状况就能够用 middleware来实现。java
你们可能频繁在view使用request.user
吧。 Django想在每一个view执行以前把user设置为request的属性,因而就用了一个中间件来实现这个目标。因此Django提供了能够修改request 对象的中间件 AuthenticationMiddleware
。python
Django默认的Middleware
:git
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
每个中间件都有具体的功能。ajax
中间件中一共有四个方法:正则表达式
process_request process_view process_exception process_response
当用户发起请求的时候会依次通过全部的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。算法
上述截图中的中间件都是django中的,咱们也能够本身定义一个中间件,咱们能够本身写一个类,可是必须继承MiddlewareMixinsql
须要导入
1
|
from
django.utils.deprecation
import
MiddlewareMixin
|
in views:
def index(request): print("view函数...") return HttpResponse("OK")
in Mymiddlewares.py:
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") def process_response(self,request,response): print("Md1返回") return response class Md2(MiddlewareMixin): def process_request(self,request): print("Md2请求")
#return HttpResponse("Md2中断") def process_response(self,request,response): print("Md2返回") return response
结果:
Md1请求 Md2请求 view函数... Md2返回 Md1返回
注意:若是当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,而后依次返回到请求者,结果以下:
返回Md2中断的页面,后台打印以下:
Md1请求 Md2请求 Md2返回 Md1返回
流程图以下:
1
|
process_view(
self
, request, callback, callback_args, callback_kwargs)
|
Mymiddlewares.py修改以下
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") #return HttpResponse("Md1中断") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("Md1view") class Md2(MiddlewareMixin): def process_request(self,request): print("Md2请求") return HttpResponse("Md2中断") def process_response(self,request,response): print("Md2返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("Md2view")
结果以下:
Md1请求 Md2请求 Md1view Md2view view函数... Md2返回 Md1返回
下图进行分析上面的过程:
当最后一个中间的process_request到达路由关系映射以后,返回到中间件1的process_view,而后依次往下,到达views函数,最后经过process_response依次返回到达用户。
process_view能够用来调用视图函数:
class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") #return HttpResponse("Md1中断") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") response=callback(request,*callback_args,**callback_kwargs) return response
结果以下:
Md1请求 Md2请求 view函数... Md2返回 Md1返回
注意:process_view若是有返回值,会越过其余的process_view以及视图函数,可是全部的process_response都还会执行。
1
|
process_exception(
self
, request, exception)
|
示例修改以下:
class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") #return HttpResponse("Md1中断") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") # response=callback(request,*callback_args,**callback_kwargs) # return response print("md1 process_view...") def process_exception(self): print("md1 process_exception...") class Md2(MiddlewareMixin): def process_request(self,request): print("Md2请求") # return HttpResponse("Md2中断") def process_response(self,request,response): print("Md2返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("md2 process_view...") def process_exception(self): print("md1 process_exception...")
结果以下:
Md1请求 Md2请求 md1 process_view... md2 process_view... view函数... Md2返回 Md1返回
流程图以下:
当views出现错误时:
将md2的process_exception修改以下:
def process_exception(self,request,exception): print("md2 process_exception...") return HttpResponse("error")
结果以下:
Md1请求 Md2请求 md1 process_view... md2 process_view... view函数... md2 process_exception... Md2返回 Md1返回
1
2
3
4
5
6
7
8
|
1
、设置Sessions值
request.session[
'session_name'
]
=
"admin"
2
、获取Sessions值
session_name
=
request.session[
"session_name"
]
3
、删除Sessions值
del
request.session[
"session_name"
]
4
、检测是否操做session值
if
"session_name"
is
request.session :
|
1
2
3
4
5
6
7
8
|
1
、设置Sessions值
request.session[
'session_name'
]
=
"admin"
2
、获取Sessions值
session_name
=
request.session[
"session_name"
]
3
、删除Sessions值
del
request.session[
"session_name"
]
4
、检测是否操做session值
if
"session_name"
is
request.session :
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
5
、get(key, default
=
None
)
fav_color
=
request.session.get(
'fav_color'
,
'red'
)
6
、pop(key)
fav_color
=
request.session.pop(
'fav_color'
)
7
、keys()
8
、items()
9
、setdefault()
10
、flush() 删除当前的会话数据并删除会话的Cookie。
这用于确保前面的会话数据不能够再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
11
用户session的随机字符串
request.session.session_key
# 将全部Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists(
"session_key"
)
# 删除当前用户的全部Session数据
request.session.delete(
"session_key"
)
request.session.set_expiry(value)
*
若是value是个整数,session会在些秒数后失效。
*
若是value是个datatime或timedelta,session就会在这个时间后失效。
*
若是value是
0
,用户关闭浏览器session就会失效。
*
若是value是
None
,session会依赖全局session失效策略。
|
views:
def log_in(request): if request.method=="POST": username=request.POST['user'] password=request.POST['pwd'] user=UserInfo.objects.filter(username=username,password=password) if user: #设置session内部的字典内容 request.session['is_login']='true' request.session['username']=username #登陆成功就将url重定向到后台的url return redirect('/backend/') #登陆不成功或第一访问就停留在登陆页面 return render(request,'login.html') def backend(request): print(request.session,"------cookie") print(request.COOKIES,'-------session') """ 这里必须用读取字典的get()方法把is_login的value缺省设置为False, 当用户访问backend这个url先尝试获取这个浏览器对应的session中的 is_login的值。若是对方登陆成功的话,在login里就已经把is_login 的值修改成了True,反之这个值就是False的 """ is_login=request.session.get('is_login',False) #若是为真,就说明用户是正常登录的 if is_login: #获取字典的内容并传入页面文件 cookie_content=request.COOKIES session_content=request.session username=request.session['username'] return render(request,'backend.html',locals()) else: """ 若是访问的时候没有携带正确的session, 就直接被重定向url回login页面 """ return redirect('/login/') def log_out(request): """ 直接经过request.session['is_login']回去返回的时候, 若是is_login对应的value值不存在会致使程序异常。因此 须要作异常处理 """ try: #删除is_login对应的value值 del request.session['is_login'] # OR---->request.session.flush() # 删除django-session表中的对应一行记录 except KeyError: pass #点击注销以后,直接重定向回登陆页面 return redirect('/login/')
template:
===================================login.html==================
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post"> <p>用户名: <input type="text" name="user"></p> <p>密码: <input type="password" name="pwd"></p> <p><input type="submit"></p> </form> </body> </html> ===================================backend.html================== <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>hello {{ username }}</h3> <a href="/logout/">注销</a> </body> </html>
(1)数据库配置(默认):
Django默认支持Session,而且默认是将Session数据存储在数据库中,即:django_session 表中。
a. 配置 settings.py
SESSION_ENGINE
=
'django.contrib.sessions.backends.db'
# 引擎(默认)
SESSION_COOKIE_NAME =
"sessionid"
# Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH =
"/"
# Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN
=
None
# Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE
=
False
# 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY
=
True
# 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE
=
1209600
# Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE
=
False
# 是否关闭浏览器使得Session过时(默认)
SESSION_SAVE_EVERY_REQUEST
=
False
# 是否每次请求都保存Session,默认修改以后才保存(默认)
2)缓存配置
a. 配置 settings.py
SESSION_ENGINE
=
'django.contrib.sessions.backends.cache'
# 引擎
SESSION_CACHE_ALIAS
=
'default'
# 使用的缓存别名(默认内存缓存,也能够是memcache),此处别名依赖缓存的设置
SESSION_COOKIE_NAME =
"sessionid"
# Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH =
"/"
# Session的cookie保存的路径
SESSION_COOKIE_DOMAIN
=
None
# Session的cookie保存的域名
SESSION_COOKIE_SECURE
=
False
# 是否Https传输cookie
SESSION_COOKIE_HTTPONLY
=
True
# 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE
=
1209600
# Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE
=
False
# 是否关闭浏览器使得Session过时
SESSION_SAVE_EVERY_REQUEST
=
False
# 是否每次请求都保存Session,默认修改以后才保存
(3)文件配置
a. 配置 settings.py
SESSION_ENGINE
=
'django.contrib.sessions.backends.file'
# 引擎
SESSION_FILE_PATH
=
None
# 缓存文件路径,若是为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
SESSION_COOKIE_NAME =
"sessionid"
# Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH =
"/"
# Session的cookie保存的路径
SESSION_COOKIE_DOMAIN
=
None
# Session的cookie保存的域名
SESSION_COOKIE_SECURE
=
False
# 是否Https传输cookie
SESSION_COOKIE_HTTPONLY
=
True
# 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE
=
1209600
# Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE
=
False
# 是否关闭浏览器使得Session过时
SESSION_SAVE_EVERY_REQUEST
=
False
# 是否每次请求都保存Session,默认修改以后才保存
1
|
from
django.contrib
import
auth
|
django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
提供了用户认证,即验证用户名以及密码是否正确,通常须要username password两个关键字参数
若是认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登陆过程当中是须要的。当咱们试图登录一个从数据库中直接取出来不通过authenticate()的User对象会报错的!!
1
|
user
=
authenticate(username
=
'someone'
,password
=
'somepassword'
)
|
该函数接受一个HttpRequest对象,以及一个认证了的User对象
此函数使用django的session框架给某个已认证的用户附加上session id等信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
from
django.contrib.auth
import
authenticate, login
def
my_view(request):
username
=
request.POST[
'username'
]
password
=
request.POST[
'password'
]
user
=
authenticate(username
=
username, password
=
password)
if
user
is
not
None
:
login(request, user)
# Redirect to a success page.
...
else
:
# Return an 'invalid login' error message.
...
|
1
2
3
4
5
|
from
django.contrib.auth
import
logout
def
logout_view(request):
logout(request)
# Redirect to a success page.
|
该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会所有清除。该用户即便没有登陆,使用该函数也不会报错。
要求:
1 用户登录后才能访问某些页面,
2 若是用户没有登陆就访问该页面的话直接跳到登陆页面
3 用户在跳转的登录界面中完成登录后,自动访问跳转到以前访问的地址
方法1:
1
2
3
|
def
my_view(request):
if
not
request.user.is_authenticated():
return
redirect(
'%s?next=%s'
%
(settings.LOGIN_URL, request.path))
|
方法2:
django已经为咱们设计好了一个用于此种状况的装饰器:login_requierd()
1
2
3
4
5
|
from
django.contrib.auth.decorators
import
login_required
@login_required
def
my_view(request):
...
|
若用户没有登陆,则会跳转到django默认的 登陆URL '/accounts/login/ ' (这个值能够在settings文件中经过LOGIN_URL进行修改)。并传递 当前访问url的绝对路径 (登录成功后,会重定向到该路径)。
User 对象属性:username, password(必填项)password用哈希算法保存到数据库
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否容许用户登陆, 设置为``False``,能够不用删除用户来禁止 用户登陆
若是是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经经过了认证。
经过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是代表用户成功的经过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登陆,若是true则能够向前台展现request.user.name
使用 create_user 辅助函数建立用户:
1
2
|
from
django.contrib.auth.models
import
User
user
=
User.objects.create_user(username
=
'
',password='
',email='
')
|
1
|
用户须要修改密码的时候 首先要让他输入原来的密码 ,若是给定的字符串经过了密码检查,返回
True
|
使用 set_password() 来修改密码
1
2
3
|
user
=
User.objects.get(username
=
'')
user.set_password(password
=
'')
user.save
|
注册:
def
sign_up(request):
state
=
None
if
request.method
=
=
'POST'
:
password
=
request.POST.get(
'password'
, '')
repeat_password
=
request.POST.get(
'repeat_password'
, '')
email
=
request.POST.get(
'email'
, '')
username
=
request.POST.get(
'username'
, '')
if
User.objects.
filter
(username
=
username):
state
=
'user_exist'
else
:
new_user
=
User.objects.create_user(username
=
username, password
=
password,email
=
email)
new_user.save()
return
redirect(
'/book/'
)
content
=
{
'state'
: state,
'user'
:
None
,
}
return
render(request,
'sign_up.html'
, content)
|
修改密码:
@login_required
def
set_password(request):
user
=
request.user
state
=
None
if
request.method
=
=
'POST'
:
old_password
=
request.POST.get(
'old_password'
, '')
new_password
=
request.POST.get(
'new_password'
, '')
repeat_password
=
request.POST.get(
'repeat_password'
, '')
if
user.check_password(old_password):
if
not
new_password:
state
=
'empty'
elif
new_password !
=
repeat_password:
state
=
'repeat_error'
else
:
user.set_password(new_password)
user.save()
return
redirect(
"/log_in/"
)
else
:
state
=
'password_error'
content
=
{
'user'
: user,
'state'
: state,
}
return
render(request,
'set_password.html'
, content)
假设你想在你的网站上建立一个简单的表单,以得到用户的名字。你须要相似这样的模板:
<form
action
=
"/your-name/"
method=
"post"
>
<label
for
=
"your_name"
>Your
name
: </label>
<input id=
"your_name"
type=
"text"
name
=
"your_name"
>
<input type=
"submit"
value=
"OK"
>
</form>
这是一个很是简单的表单。实际应用中,一个表单可能包含几十上百个字段,其中大部分须要预填充,并且咱们预料到用户未来回编辑-提交几回才能完成操做。
咱们可能须要在表单提交以前,在浏览器端做一些验证。咱们可能想使用很是复杂的字段,以容许用户作相似从日历中挑选日期这样的事情,等等。
这个时候,让Django 来为咱们完成大部分工做是很容易的。
so,两个突出优势:
1 form表单提交时,数据出现错误,返回的页面中仍能够保留以前输入的数据。
2 方便地限制字段条件
咱们已经计划好了咱们的 HTML 表单应该呈现的样子。在Django 中,咱们的起始点是这里:
#forms.py
from
django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label=
'Your name'
, max_length=100)
它定义一个Form
类,只带有一个字段(your_name
)。
字段容许的最大长度经过max_length
定义。它完成两件事情。首先,它在HTML 的<input>
上放置一个maxlength="100"
(这样浏览器将在第一时间阻止用户输入多于这个数目的字符)。它还意味着当Django 收到浏览器发送过来的表单时,它将验证数据的长度。
Form
的实例具备一个is_valid()
方法,它为全部的字段运行验证的程序。当调用这个方法时,若是全部的字段都包含合法的数据,它将:
True
cleaned_data
属性中。完整的表单,第一次渲染时,看上去将像:
<label
for
=
"your_name"
>Your
name
: </label>
<input id=
"your_name"
type=
"text"
name
=
"your_name"
maxlength=
"100"
>
注意它不包含 <form>
标签和提交按钮。咱们必须本身在模板中提供它们。
发送给Django 网站的表单数据经过一个视图处理,通常和发布这个表单的是同一个视图。这容许咱们重用一些相同的逻辑。
当处理表单时,咱们须要在视图中实例化它:
#views.py from django.shortcuts import render from django.http import HttpResponseRedirect from .forms import NameForm def get_name(request): # if this is a POST request we need to process the form data if request.method == 'POST': # create a form instance and populate it with data from the request: form = NameForm(request.POST) # check whether it's valid: if form.is_valid(): # process the data in form.cleaned_data as required # ... # redirect to a new URL: return HttpResponseRedirect('/thanks/') # if a GET (or any other method) we'll create a blank form else: form = NameForm() return render(request, 'name.html', {'form': form})
若是访问视图的是一个GET
请求,它将建立一个空的表单实例并将它放置到要渲染的模板的上下文中。这是咱们在第一个访问该URL 时预期发生的状况。
若是表单的提交使用POST
请求,那么视图将再次建立一个表单实例并使用请求中的数据填充它:form = NameForm(request.POST)
。这叫作”绑定数据至表单“(它如今是一个绑定的表单)。
咱们调用表单的is_valid()
方法;若是它不为True
,咱们将带着这个表单返回到模板。这时表单再也不为空(未绑定),因此HTML 表单将用以前提交的数据填充,而后能够根据要求编辑并改正它。
若是is_valid()
为True
,咱们将可以在cleaned_data
属性中找到全部合法的表单数据。在发送HTTP 重定向给浏览器告诉它下一步的去向以前,咱们能够用这个数据来更新数据库或者作其它处理。
咱们不须要在name.html 模板中作不少工做。最简单的例子是:
<form
action
=
"/your-name/"
method=
"post"
>
{% csrf_token %}
{{ form }}
<input type=
"submit"
value=
"Submit"
/>
</form>
根据{{ form }}
,全部的表单字段和它们的属性将经过Django 的模板语言拆分红HTML 标记 。
注:Django 原生支持一个简单易用的跨站请求伪造的防御。当提交一个启用CSRF 防御的POST
表单时,你必须使用上面例子中的csrf_token
模板标签。
如今咱们有了一个能够工做的网页表单,它经过Django Form 描述、经过视图处理并渲染成一个HTML <form>
。
绑定的和未绑定的表单 之间的区别很是重要:
考虑一个比上面的迷你示例更有用的一个表单,咱们完成一个更加有用的注册表单:
#forms.py from django import forms class RegisterForm(forms.Form): username = forms.CharField(max_length=100, error_messages={"min_length":"最短为5个字符","required":"该字段不能为空"}, ) password = forms.CharField(max_length=100, widget=widgets.PasswordInput(attrs={"placeholder":"password"}) ) telephone=forms.IntegerField( error_messages={ "invalid":"格式错误" } ) gender=forms.CharField( initial=2, widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) ) email = forms.EmailField() is_married = forms.BooleanField(required=False)
每一个表单字段都有一个对应的Widget
类,它对应一个HTML 表单Widget
,例如<input type="text">
。
在大部分状况下,字段都具备一个合理的默认Widget。例如,默认状况下,CharField
具备一个TextInput Widget
,它在HTML 中生成一个<input type="text">
。
无论表单提交的是什么数据,一旦经过调用is_valid()
成功验证(is_valid()
返回True
),验证后的表单数据将位于form.cleaned_data
字典中。这些数据已经为你转换好为Python 的类型。
注:此时,你依然能够从request.POST
中直接访问到未验证的数据,可是访问验证后的数据更好一些。
在上面的联系表单示例中,is_married将是一个布尔值。相似地,IntegerField
和FloatField
字段分别将值转换为Python 的int
和float
。
你须要作的就是将表单实例放进模板的上下文。若是你的表单在Contex
t 中叫作form
,那么{{ form }}
将正确地渲染它的<label>
和 <input>
元素。
对于<label>/<input>
对,还有几个输出选项:
{{ form.as_table }}
以表格的形式将它们渲染在<tr>
标签中{{ form.as_p }}
将它们渲染在<p>
标签中{{ form.as_ul }}
将它们渲染在<li>
标签中注意,你必须本身提供<table>
或<ul>
元素。
{{ form.as_p }}
会渲染以下:
<
form
action="">
<
p
>
<
label
for="id_username">Username:</
label
>
<
input
id="id_username" maxlength="100" name="username" type="text" required="">
</
p
>
<
p
>
<
label
for="id_password">Password:</
label
>
<
input
id="id_password" maxlength="100" name="password" placeholder="password" type="password" required="">
</
p
>
<
p
>
<
label
for="id_telephone">Telephone:</
label
> <
input
id="id_telephone" name="telephone" type="number" required="">
</
p
>
<
p
>
<
label
for="id_email">Email:</
label
> <
input
id="id_email" name="email" type="email" required="">
</
p
>
<
p
>
<
label
for="id_is_married">Is married:</
label
> <
input
id="id_is_married" name="is_married" type="checkbox">
</
p
>
<
input
type="submit" value="注册">
</
form
>
咱们没有必要非要让Django 来分拆表单的字段;若是咱们喜欢,咱们能够手工来作(例如,这样容许从新对字段排序)。每一个字段都是表单的一个属性,可使用{{ form.name_of_field }}
访问,并将在Django 模板中正确地渲染。例如:
<
div
class="fieldWrapper">
{{ form.Username.errors }}
{{ form.Username.label_tag }}
{{ form.Username }}
</
div
>
一、
registerForm=RegisterForm(request.POST)
print(type(registerForm.errors)) #<
class
'django.forms.utils.ErrorDict'>
print(type(registerForm.errors["username"])) #<
class
'django.forms.utils.ErrorList'>
二、
使用{{ form.name_of_field.errors }}
显示表单错误的一个清单,并渲染成一个ul
。看上去可能像:
<
ul
class="errorlist">
<
li
>Sender is required.</
li
>
</
ul
>
def foo(request): if request.method=="POST": regForm=RegForm(request.POST) if regForm.is_valid(): pass # 可用数据: regForm.cleaned_data, # 将数据插入数据库表中 else: pass # 可用数据: regForm.errors # 能够利用模板渲染讲errors嵌套到页面中返回 # 也能够打包到一个字典中,用于ajax返回 else: regForm=RegForm() return render(request,"register.html",{"regForm":regForm}) ''' 实例化时: self.fields={ "username":"字段规则对象", "password":"字段规则对象", } is_valid时: self._errors = {} self.cleaned_data = {} #局部钩子: for name, field in self.fields.items(): try: value = field.clean(value) self.cleaned_data[name] = value if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value except ValidationError as e: self.add_error(name, e) # 全局钩子: self.clean() # def self.clean():return self.cleaned_data return not self.errors # True或者False '''
一、Django内置字段以下:
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
三、经常使用选择插件:
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 单radio,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 单select,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多选select,值为列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 单checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多选checkbox,值为列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
引入:
https://www.cnblogs.com/wupeiqi/articles/6144178.html