在Django MVC概述和开发流程中已经讲解了Django的MVT开发流程,本文重点对MVT中的视图(View)进行重点讲解。
Django视图层主要工作是衔接模型和模板,接收请求,进行处理,返回应答。
URL参数
进行url匹配时,把所需要传递的参数设置成一个正则表达式组,Django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。
- 1.位置参数
url(r'^index(d )$', views.index)
- 2.关键字参数:在位置参数的基础上给正则表达式组命名即可。
url(r'^index(?P<num>d )$', views.index)
设置了关键字参数后,视图中参数名必须和正则表达式组名一致。
HttpReqeust对象
服务器接收到http协议的请求后,会根据报文创建HttpRequest对象,这个对象不需要手动创建,直接使用构造好的对象即可。视图的第一个参数必须是HttpRequest对象(一般定义视图时,参数写request),在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对象
HttpRequest对象的GET和POST属性都是QueryDict类型的对象,该类型定义在django.http.QueryDict中。类python字典的类型,但与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况。
get方法
根据键获取值。如果一个键同时拥有多个值将获取最后一个值,如果键不存在则返回None值,可以设置默认值进行后续处理
代码语言:javascript复制dict.get('键', 默认值)
# 可简写为
dict['键']
getlist方法
根据键获取多个值,返回的是一个列表。如果键不存在则返回空列表[],也可以设置默认值进行后续处理
代码语言:javascript复制dict.getlist('键', 默认值)
处理表单
以一个登陆demo做示例讲解,首先添加login.html,内容如下
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
</head>
<body>
<form action="/login_handle" method="post">
账号 <input type="text" name="username"> <br>
密码 <input type="password" name="password"> <br>
<input type="submit" value="登陆">
</form>
</body>
</html>
通过request.POST.get(‘键’)可以获取表单提交的信息,对应的视图处理函数如下
代码语言:javascript复制def login(request):
return render(request, 'school_test/login.html')
def login_handle(request):
# 通过 request.POST.get 方法获取表单提交的信息
username = request.POST.get('username')
password = request.POST.get('password')
return HttpResponse(username ":" password)
关闭csrf防御(django默认开启csfr防御,在提交表单时会返回403错误,这里不作介绍csrf,后续会在讲解模板的文章中介绍)
在settings.py中注释掉下面这行
配置url映射
代码语言:javascript复制urlpatterns = [
url(r'^login$', views.login),
url(r'^login_handle$', views.login_handle),
]
HttpResponse对象
视图在接收请求并处理后,必须返回HttpResponse类的实例对象或者子类实例对象。在django.http模块中定义了HttpResponse对象的API。HttpRequest对象由Django框架自动创建,HttpResponse对象则由开发人员创建。
属性
- content:表示返回的内容。
- charset:表示response采用的编码字符集,默认为utf-8。
- status_code:返回的HTTP响应状态码。
- content-type:指定返回数据的的MIME类型,默认为’text/html’。
JsonResponse 和 AJAX
这里使用jQuery来发起ajax请求,所以需要引入jQuery文件。css、js、图片等都属于静态文件,在项目根目录下创建static目录,然后在static目录下创建css、js、images目录,在js目录中导入jQuery文件。现Django项目目录结构如下。
然后在settings.py中设置静态文件目录
代码语言:javascript复制STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
在浏览器中使用js发起ajax请求时,返回json格式的数据,此处以jquery的get()方法为例。JsonResponse继承自HttpResponse类,被定义在django.http模块中,创建对象时接收字典作为参数。同样以一个登陆demo做示例讲解,创建login_ajax.html文件。
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆 ajax</title>
<script src="/static/js/jquery-1.11.1.min.js"></script>
<script>
$(function () {
// 绑定点击事件
$('#login').click(function() {
let username = $('#username').val()
let password = $('#password').val()
// 发起ajax请求
$.ajax({
'url': '/login_ajax_handle',
'dataType': 'json',
'type': 'post',
// 发送的json数据
'data': {'username': username, 'password': password},
}).success(function (data) {
// 处理后台返回的json数据
if (data.stat == 1) {
$('#stat').show().html('登陆成功')
} else if (data.stat == 0) {
$('#stat').show().html('登陆失败')
}
})
})
})
</script>
<style>
#stat {
color: red;
display: none;
}
</style>
</head>
<body>
<div>
账号:<input type="text" id="username"> <br>
密码:<input type="password" id="password"> <br>
<input type="button" id="login" value="登陆">
</div>
<div id="stat"></div>
</body>
</html>
通过构建JsonResponse对象返回给前端ajax请求一个json数据,在django.http模块中定义了JsonResponse类,对应的视图处理函数如下
代码语言:javascript复制from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
def login_ajax(request):
return render(request, "school_test/login_ajax.html")
def login_ajax_handle(request):
# 通过 request.POST.gheet 方法获取 ajax 提交的信息
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'requestroot' and password == '123':
# 构建 JsonResponse 对象返回一个json数据
return JsonResponse({'stat': 1})
else:
return JsonResponse({'stat': 0})
HttpResponseRedirect 和 页面重定向
当一个逻辑处理完成后,不需要向客户端呈现数据,而是转回到其它页面,如添加成功、修改成功、删除成功后显示数据列表,此时就需要模拟一个用户请求的效果,从一个视图转到另外一个视图,就称为重定向。
Django中提供了HttpResponseRedirect对象实现重定向功能,这个类继承自HttpResponse,被定义在django.http模块中,返回的状态码为302。
代码语言:javascript复制from django.http import HttpResponseRedirect
# 定义重定义向视图,转向首页
def red1(request):
return HttpResponseRedirect('/index')
在django.shortcuts模块中为重定向类提供了简写redirect函数。
代码语言:javascript复制from django.shortcuts import redirect
# 定义重定义向视图,转向首页
def red1(request):
return redirect('/index')
状态保持
http请求是无状态的。无状态指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
无状态原因是:浏览器与服务器是使用socket进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
有时需要保存下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等。 实现状态保持主要有两种方式:
- 在客户端存储信息使用Cookie。
- 在服务器端存储信息使用Session。
Cookie
Cookie由服务器生成,并存储在浏览器里的一段数据。
Cookie特点:
- 以键值对方式存储。
- Cookie是基于域名安全的。通过浏览器访问网站时,会将浏览器存储的只跟本网站相关的所有Cookie信息发送给该网站的服务器。
- Cookie是有过期时间的,可以指定过期时间,默认在关闭浏览器之后cookie就会过期。
以一个登陆demo做示例讲解,利用Cookie记住用户名,由于密码是敏感信息,会在下文Session中进行保存,这里不做保存。在之前创建的login.html文件里加入一个单选框。
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
</head>
<body>
<form action="/login_handle" method="post">
账号 <input type="text" name="username" value="{{ username }}"> <br>
密码 <input type="password" name="password"> <br>
<input type="checkbox" name="check"> 记住用户名和密码 <br>
<input type="submit" value="登陆">
</form>
</body>
</html>
在后台通过在HttpResponse对象中调用set_cookie方法设置Cookie,然后返回给浏览器。在浏览器请求网页时,Cookie保存在request中,可以通过request.COOKIES.get(‘键’)读取Cookide。在views.py中更改login、login_handle视图函数。
代码语言:javascript复制def login(request):
# 读取Cookie中username的值,并将值传递给模板
username = request.COOKIES.get('username', '')
return render(request, 'school_test/login.html', {'username': username})
def login_handle(request):
username = request.POST.get('username')
password = request.POST.get('password')
# 获取单选框状态
check = request.POST.get('check')
response = HttpResponse(username ":" password)
# 单选框选中下,保存Cookie到HttpResponse对象中
if check == 'on':
# max_age=7*24*3600 指定两周后过期 (以s为单位)
response.set_cookie('username', username, max_age=7*24*3600)
return response
Session
对于敏感、重要的信息,应该存储在服务器端,而不能存储在浏览器中。在服务器进行状态保存用的是Session,Session存储在服务端。为了解决Cookie的安全隐患问题,采用将用户的数据保存在服务端,然后在客户端浏览器里Cookie加入一个对应的sessionid(随机字符串)。
Session工作流程:
- 1.当浏览器请求网页时,在后台处理并设置Session信息,并随机生成一个字符串作为该Session的唯一标识,并把该唯一标识封装在{sessionid: 唯一标识}返回给浏览器并设置为Cookie
- 2.当浏览器再次访问该网站时,将Cookie发送给服务器,后台在Cookie的sessionid中取出唯一标识,再根据sessionid即可获取上次在服务端存储的Session。
django默认将Session信息存储在当前连接数据库的django_session数据表中。 注: Session工作流程由Django框架自动完成。
Session的特点:
- 以键值对方式存储。
- Session依赖于Cookie。唯一的标识码保存在Cookie的sessionid中。
- Session也是有过期时间,如果不指定,默认为两周。
之前的登陆demo已经通过Cookie来保存了用户名,这里用Session来保存密码。login.html文件内容如下
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
</head>
<body>
<form action="/login_handle" method="post">
账号 <input type="text" name="username" value="{{ username }}"> <br>
密码 <input type="password" name="password" value="{{ password }}"> <br>
<input type="checkbox" name="check"> 记住用户名和密码 <br>
<input type="submit" value="登陆">
</form>
</body>
</html>
通过request.session可以对Session进行读写。在views.py中更改login、login_handle视图函数。
代码语言:javascript复制def login(request):
# 读取Cookie中username的值,并将值传递给模板
username = request.COOKIES.get('username', '')
# 读取Session中password的值,并将值传递给模板
password = request.session.get('password', '')
return render(request, 'school_test/login.html', {'username': username, 'password': password})
def login_handle(request):
username = request.POST.get('username')
password = request.POST.get('password')
# 获取单选框状态
check = request.POST.get('check')
response = HttpResponse(username ":" password)
# 单选框选中下,保存Cookie到HttpResponse对象中,Session到HttpRequest对象中
if check == 'on':
# 设置Cookie
response.set_cookie('username', username, max_age=7*24*3600)
# 设置Session
request.session['password'] = password
return response
View.as_view方法
上面代码使用了login
和login_handle
函数分别对登陆页面的get和post请求做了处理, 其视图函数对应着两个url. 实际上可以用同一个url和同一个视图函数进行处理
def login_view(request):
if request.method == 'GET':
# 处理get请求
return login(request)
elif request.method == 'POST':
# 处理post请求
return login_handle(request)
代码语言:javascript复制urlpatterns = [
url(r'^login$', views.login_view),
]
除了使用如上方式, 也可以使用类视图对get和post进行封装
代码语言:javascript复制from django.views.generic import View
class LoginView(View):
def get(self, request):
# 处理get请求
return login(request)
def post(self, request):
# 处理post请求
return login_handle(request)
代码语言:javascript复制urlpatterns = [
# 使用as_view方法进行url映射
url(r'^login$', LoginView.as_view()),
]
本文作者: Ifan Tsai (菜菜)
本文链接: https://cloud.tencent.com/developer/article/2164570
版权声明: 本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!