Django MVT之V

2022-11-15 21:12:45 浏览数 (1)

在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方法

上面代码使用了loginlogin_handle函数分别对登陆页面的get和post请求做了处理, 其视图函数对应着两个url. 实际上可以用同一个url和同一个视图函数进行处理

代码语言:javascript复制
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 国际许可协议 进行许可。转载请注明出处!

0 人点赞