03 Django视图
-
功能
- 接受Web请求HttpRequest,进行逻辑处理,与 M 和 T 进行交互,返回 Web 响应 HttpResponse 给请求者
-
示例项目的创建
-
创建项目 test3
-
django-admin startproject test3 |
-
进入项目目录后,创建应用 booktest
cd test3 python manage.py startapp booktest |
-
在 test3/settings.py 中 INSTALLED_APPS 项安装应用
- 在 test3/settings.py 中 DATABASES 项配置使用 MYSQL 数据库,参照配置使用 mysql 数据库
- 在 test3/settings.py 中 TEMPLATES 项配置模板查找路径,参照模板文件的使用
-
使用示图的过程
- 视图就是一个python函数,被定义在"应用/views.py"文件中。 使用视图时需要进行两方面操作,两个操作不分先后
-
在 '应用/views.py' 中定义视图
-
在 booktest/views.py 中定义视图函数index
-
def index(request): return HttpResponse("视图函数index") |
-
配置URLconf,将视图函数和url对应起来
-
在test3/urls.py中编辑加入如下代码:
-
from django.conf.urls import include, url from django.contrib import admin
urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^', include('booktest.urls')), #这句代码是新加入的,包含booktest应用中的urls文件 ]
|
-
在booktest目录下创建urls.py文件并编辑其内容如下:
from django.conf.urls import url #导入url函数
from booktest import views #导入视图模块
urlpatterns = [ url(r'^$', views.index), #建立url和views.index视图函数的关联 ]
|
-
启动服务器,并通过浏览器访问 http://127.0.0.1:8000, 页面显示如下:
-
url 匹配过程
-
示意图
-
过程,以访问 http://127.0.0.1:8000/aindex?a=1 为例,请求的url被看做是一个普通的python字符串,进行匹配时不包括域名、get或post参数
- 去除域名和后面的参数,剩下 /aindex,再把前面的的 / 去掉,剩下 aindex
- 拿 aindex 先到项目的 url.py 文件中进行从上到下的匹配,匹配成功之后执行后面对应的处理动作。对于图中的示例来说,就是把匹配成功的部分 a 字符去除,然后拿剩下的部分 index 到应用的 urls.py 文件中再进行从上到下的匹配
- 如果匹配成功,则调用相应的视图产生的内容返回给客户端。如果匹配失败则产生 404 错误
-
-
错误视图
-
404
- 找不到页面,关闭调试模式之后,默认会显示一个标准的错误页面,如果要显示自定义的页面,则需要在 templates 目录下面自定义一个 404.html 文件
-
出现 404 的可能原因
- url 没有配置
- url 配置错误
-
500
- 服务器错误,默认会显示一个标准的错误页面,如果要显示自定义的页面,则需要在 templates 目录下面自定义一个 500.html 文件
-
出现 500 的可能原因
- 视图出错
-
-
捕获 url 参数
-
位置参数
- 直接使用小括号,通过位置参数传递给视图。
-
使用如下的正则表达式
-
url(r'^delete(\d+)/$',views.show_arg), |
-
修改视图 show_arg 如下:
- 其中参数的名字可以为任意值,但尽量要做到见名知意
def show_arg(request,id): return HttpResponse('show arg %s'%id) |
-
在浏览器中输入相应的地址,如下:
-
关键字参数
- 在正则表达式部分为组命名
-
正则表达式如下:
# 其中?P部分表示为这个参数定义的名称为id,可以是其它名称,起名做到见名知意。 url(r'^delete(?P<id1>\d+)/$',views.show_arg), |
-
修改视图 show_arg 如下:
# 注意:视图show_arg此时必须要有一个参数名为id1,否则报错。 def show_arg(request,id1): return HttpResponse('show %s'%id1) |
-
在浏览器中输入相应地址,结果如下:
-
HttpRequest 对象
- 服务器接收到 http 协议的请求后,会根据报文创建 HttpRequest 对象,这个对象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数必须是 HttpRequest 对象,在django.http 模块中定义了HttpRequest 对象的 API
-
属性(除非特殊说明,属性都是只读的)
- path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
-
method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。
- 在浏览器中给出地址发出请求采用get方式,如超链接。
- 在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求。
-
encoding:一个字符串,表示提交的数据的编码方式。
- 如果为None则表示使用浏览器的默认设置,一般为utf-8。
- 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
- GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数。
- POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数。
- FILES:一个类似于字典的对象,包含所有的上传文件。
- COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串。
- session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见"状态保持"。
-
QueryDict 对象
- 定义在django.http.QueryDict
- HttpRequest对象的属性GET、POST都是QueryDict类型的对象
- 与 python 字典不同,QueryDict类型的对象可以用来处理同一个键带有多个值的情况
-
方法 get():根据键获取值
- 如果一个键同时拥有多个值将获取最后一个值
- 如果键不存在则返回None值,可以设置默认值进行后续处理
-
示例
dict.get('键',默认值) # 可简写为 dict['键'] |
-
方法 getlist():根据键获取值,值以列表返回,可以获取指定键的所有值
- 如果键不存在则返回空列表 [],可以设置默认值进行后续处理
dict.getlist('键',默认值) |
-
HttpResponse 对象
-
相关概念
- 视图在接收请求并处理后,必须返回HttpResponse对象或子对象
- 在django.http模块中定义了HttpResponse对象的API
- HttpRequest对象由Django创建,HttpResponse对象由开发人员创建
-
属性
- content:表示返回的内容。
- charset:表示response采用的编码字符集,默认为utf-8。
- status_code:返回的HTTP响应状态码。
- content-type:指定返回数据的的MIME类型,默认为'text/html'
-
方法
- __init__:创建HttpResponse对象后完成返回内容的初始化
-
write:向响应体中写数据
-
def get_cookie(request): """获取 cookie 值""" response = HttpResponse("<h1>获取 cookie 值</h1><br />") if 'username' in request.COOKIES: response.write("<h2>username: " + request.COOKIES['username'] + "</h2>") else: response.write("用户名不存在") return response |
-
使用示例
from django.template import RequestContext, loader ... def index3(request): #加载模板 t1=loader.get_template('booktest/index3.html') #构造上下文 context=RequestContext(request,{'h1':'hello'}) #使用上下文渲染模板,生成字符串后返回响应对象 return HttpResponse(t1.render(context)) |
-
每次调用模板时都要执行加载、构造上下文、渲染三个步骤,为了简化操作,Django定义了render() 函数封装了以上三个步骤的代码,定义在django.shortcuts 模块中
from django.shortcuts import render ... def index3(request): return render(request, 'booktest/index3.html', {'h1': 'hello'}) |
-
示例:普通用户登录案例
-
显示出登录界面
-
设计 url, 通过浏览器访问 http://127.0.0.1:8000/login 时显示登录界面
-
-
url(r'^login$', views.login), |
-
设计 url 对应的视图函数 login
def login(request): """显示登录界面""" print(request.method) return render(request, 'booktest/login.html') |
-
编写模板文件 login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form method="post", action="/login_check"> 用户名:<input tyep='text' name='username'><br/> 密码:<input type='password', name='password'><br/> <input type='submit' value='登录'> </form> </body> </html> |
-
登录校验功能
-
设计 url,点击登录页的登录按钮发起请求 http://127.0.0.1:8000/login_check 进行登录校验
-
url(r'^login_check$', views.login_check), |
-
设计 url 对应的视图函数 login_check
- 接收表单提交过来的数据并进行登录校验,若用户名密码正确则跳转到登录成功页。若失败在跳转到登录页面。
def login_check(request): """登录校验视图""" # request.POST 保存的是 post 方式提交的参数,类型为 QueryDict # request.GET 保存的是 get 方式提交的参数, 类型为 QueryDict # 获取提取的用户名和密码 username = request.POST.get('username', 'default') password = request.POST.get('password', 'default') print(username + ':' + password) # 进行检验 if(username == 'admin' and password == '123'): # 用户名或密码正确 return redirect("/index") else: return redirect("/login") |
-
Ajax 请求与 JsonResponse
- 在浏览器中使用javascript发起ajax请求时,需要返回json格式的数据。
-
类JsonResponse继承自HttpResponse对象,被定义在django.http模块中
- 创建对象时接收字典作为参数
- JsonResponse对象的content-type为'application/json'
-
示例:ajax 登录案例
-
创建目录 static/js/,并把 jquery 文件拷贝到相应的目录下
-
打开test3/settings.py文件,在文件最底部,配置静态文件查找路径
-
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] |
-
显示出登录界面
-
设计 url,通过浏览器访问 http://127.0.0.1:8000/login_ajax 时显示登录页面
-
url(r'^login_ajax$', views.login_ajax), |
-
设计 url 对应的视图函数 login_ajax
def login_ajax(request): """ajax 登录界面""" return render(request, 'booktest/login_ajax.html') |
-
编写模板文件 login_ajax.html
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>登录页面</title> <script src='static/js/jquery-1.12.4.min.js'></script> <script> $(function(){ $('#btn').click(function(){ username = $('#username').val() password = $('#password').val() $.ajax({ 'url': '/login_ajax_check', 'type': 'post', 'data': {'username': username, 'password': password}, 'dataType': 'json', }).success(function(data){ // {'res': 1} 表示登录成功 // {'res': 0} 表示登录失败 if(data.res == 1){ location.href = '/index' } else{ $('#message').show() } }) }) }) </script> <style> #message{ display:none; color: red; } </style> </head> <body> <div> 用户名:<input tyep='text' id='username'><br/> 密码:<input type='password' id='password'><br/> <input type='button' id='btn' value='登录'> <div id="message">用户名或密码错误</div> </div> </body> </html>
|
-
登录校验功能
-
设计 url, 点击登录页的登录按钮发起请求 http://127.0.0.1:8000/login_ajax_check 进行登录校验
-
url(r'^login_ajax_check$', views.login_ajax_check), |
-
设计 url 对应的视图函数 login_ajax_check
def login_ajax_check(request): """ajax 登录界面用户名和密码检查""" username = request.POST.get('username') password = request.POST.get('password') if(username == 'admin' and password == '123'): # 用户名或密码正确 return JsonResponse({'res': 1}) else: return JsonResponse({'res': 0}) |
-
HttpResponseRedriect
- 当一个逻辑处理完成后,不需要向客户端呈现数据,而是转回到其它页面,如添加成功、修改成功、删除成功后显示数据列表,而数据的列表视图已经开发完成,此时不需要重新编写列表的代码,而是转到这个视图就可以,此时就需要模拟一个用户请求的效果,从一个视图转到另外一个视图,就称为重定向
- Django中提供了 HttpResponseRedirect 对象实现重定向功能,这个类继承自 HttpResponse,被定义在django.http模块中,返回的状态码为302
- 在 django.shortcuts 模块中为重定向类提供了简写函数 redirect
-
状态保持
-
基本概念
-
浏览器请求服务器是无状态的。
- 无状态指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
- 无状态的应用层面的原因是:浏览器和服务器之间的通信都遵守HTTP协议
- 根本原因是:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
-
有时需要保存下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等。 实现状态保持主要有两种方式:
- 在客户端存储信息使用Cookie
- 在服务器端存储信息使用Session
-
-
Cookie
-
基本概念
- Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie 最早是网景公司的前雇员 Lou Montulli 在1993年3月的发明。Cookie 是由服务器端生成,发送给 User-Agent (一般是浏览器),浏览器会将 Cookie 的 key/value 保存到某个目录下的文本文件内,下次请求同一网站时就发送该 Cookie 给服务器(前提是浏览器设置为启用 cookie)。Cookie 名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用 Cookies 包含信息的任意性来筛选并经常性维护这些信息,以判断在 HTTP 传输中的状态。
- Cookie 是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
-
特点
- Cookie 以键值对的格式进行信息的存储
- Cookie 基于域名安全,不同域名的 Cookie 是不能互相访问的,如访问 itcast.cn 时向浏览器中写了 Cookie 信息,使用同一浏览器访问baidu.com 时,无法访问到 itcast.cn 写的 Cookie 信息
- 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有 Cookie 信息提交给网站服务器
-
典型应用
- 记住用户名
- 网站的广告推送
-
在 danjo 中,对 cookie 进行操作,需要一个 HttpResponse 或其子类的对象,相关函数如下:
-
set_cookie:设置Cookie信息
-
-
-
set_cookie(key, value='', max_age=None, expires=None) |
- cookie 是网站以键值对格式存储在浏览器中的一段纯文本信息,用于实现用户跟踪
- max_age 是一个整数,表示在指定秒数后过期。
- expires 是一个 datetime 或 timedelta 对象,会话将在这个指定的日期/时间过期
- max_age 与 expires 二选一
- 如果不指定过期时间,在关闭浏览器时 cookie 会过期。
- delete_cookie(key):删除指定的 key 的Cookie,如果 key 不存在则什么也不发生。
-
设置 cookie
-
打开 booktest/views.py 文件,创建视图 cookie_set
-
def cookie_set(request): response = HttpResponse("<h1>设置Cookie,请查看响应报文头</h1>") response.set_cookie('h1', '你好') return response |
-
打开 booktest/urls.py 文件,配置 url
url(r'^cookie_set/$',views.cookie_set), |
-
在"开发者工具"中可以在响应头中查看到设置的 Cookie 信息
-
读取 cookie
- Cookie 信息被包含在请求头中,使用 request 对象的 COOKIES 属性访问
-
打开booktest/views.py文件,创建视图cookie_get
def cookie_get(request): response = HttpResponse("读取Cookie,数据如下:<br>") if 'h1' in request.COOKIES: response.write('<h1>' + request.COOKIES['h1'] + '</h1>') return response |
-
打开 booktest/urls.py 文件,配置 url
url(r'^cookie_get/$',views.cookie_get), |
-
打开"开发者工具",在请求头中可以查看Cookie信息,浏览效果如下图
-
Session
- 对于敏感、重要的信息,建议要储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息。在服务器端进行状态保持的方案就是Session
-
启用 Session
- Django项目默认启用Session
-
打开 test3/settings.py文件,项 MIDDLEWARE_CLASSES 中为启用 Session 中间件
- 禁用 session:将 session 中间件删除即可
-
存储方式
- 打开test3/settings.py文件,设置SESSION_ENGINE项指定Session数据存储的方式,可以存储在数据库、缓存、Redis等
-
储存在数据库中,如下设置可以写,也可不写,是默认的存储方式
SESSION_ENGINE='django.contrib.sessions.backends.db' |
-
存储在缓存中:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快
SESSION_ENGINE='django.contrib.sessions.backends.cache' |
-
混合存储:优先从本机内存中存取,如果没有则从数据库中存取
SESSION_ENGINE='django.contrib.sessions.backends.cached_db' |
-
如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用
-
迁移后会在数据库中创建出储存 Session 的表
-
表结构如下图
- 由表结构可知,操作Session包括三个数据:键,值,过期时间
-
依赖于 Cookie
- 在使用 Session 后,会在 Cookie 中存储一个 sessionid 的数据,每次请求时浏览器都会将这个数据发给服务器,服务器在接收到sessionid 后,会根据这个值找出这个请求者的 Session
- 因此如果想使用Session,浏览器必须支持Cookie,否则就无法使用Session了
- 存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置
-
对象及方法
- 通过 HttpRequest 对象的 session 属性进行会话的读写操作
-
以键值对的格式写session
request.session['键']=值 |
-
根据键读取值
request.session.get('键',默认值) |
-
清除所有session,在存储中删除值部分,保留 sessionid 和 {}
request.session.clear() |
-
清除 session 数据,在存储中删除 session 的整条数据
request.session.flush() |
-
删除session中的指定键及值,在存储中只删除某个键及对应的值
del request.session['键'] |
-
设置会话的超时时间,如果没有指定过期时间则两个星期后过期
request.session.set_expiry(value) # 如果value是一个整数,会话将在value秒没有活动后过期 # 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期 # 如果value为None,那么会话永不过期 |
-
示例
-
写 session
-
打开booktest/views.py文件,创建视图session_test
-
-
def session_test(request): request.session['h1']='hello' return HttpResponse('写session') |
-
打开booktest/urls.py文件,配置url
url(r'^session_test/$',views.session_test), |
-
运行服务器,打开浏览器请求如下网址
-
浏览效果如下图,在"开发者工具"中可以查看到响应头中创建了 Cookie,里面有个键为 sessionid
-
打开MySQL数据库命令行,查询数据如下图
- 查看Cookie中的sessionid值为"l48euizwnd0u1vrq401rwc9yqxkj4ip4",数据表中session的键为"l48euizwnd0u1vrq401rwc9yqxkj4ip4",是一样的,这样,服务器就可以在众多的请求者中找到对应的Session数据。
-
在MySQL数据库命令行中复制值,在Base64解码中进行解码查看如下图
-
读 session
-
打开booktest/views.py文件,修改session_test视图如下
-
def session_test(request): # request.session['h1']='hello' h1=request.session.get('h1') return HttpResponse(h1) |
-
刷新浏览器效果如下图
-
删除
-
打开booktest/views.py文件,修改session_test视图如下
-
def session_test(request): # request.session['h1']='hello' # h1=request.session.get('h1') del request.session['h1'] return HttpResponse('ok')
|
-
刷新浏览器,在数据库命令行中查询,base64解码后如下图
- 如果将所有的键及值都删除,逐个调用del太麻烦,可以使用clear()方法
-
删除 session
-
打开booktest/views.py文件,修改session_test视图如下:
-
def session_test(request): # request.session['h1']='hello' # h1=request.session.get('h1') # del request.session['h1'] request.session.flush() return HttpResponse('ok') |
-
刷新浏览器,在数据库命令行中查询如下图
-
相关操作
- 关闭调试模式的方法
- post 方法出现 403 Forbidden 时处理方法
-
相关知识
-
表单 form 提交参数的过程
-
表单控件name属性的值作为键,value 属性的值为值,构成键值对提交
- 如果表单控件没有 name 属性则不提交
- 对于 checkbox 控件,name 属性的值相同为一组,被选中的项会被提交,出现一键多值的情况
- 键是表单控件 name 属性的值,是由开发人员编写的
- 值是用户填写或选择的
-
-