Django视图

和自甴很熟 提交于 2020-01-29 11:24:30

Django中视图的功能:

  • 接收请求,进行处理,与M和T进行交互,返回应答
  • 返回html内容HttpResponse、重定向页面redirect、json数据及异常等

1. 视图函数

定义视图函数:参数:request(必须),返回一个HttpResponse类型的对象或者HTTP404异常(参数名可以自定义不建议修改)
URL配置:建立URL与视图函数之间的对应关系

URL配置

  • 在项目的urls文件中包含具体应用的urls文件,在具体应用的urls文件中包含具体url和视图的对应关系
  • url配置项定义在一个名叫urlpatterns的列表中,其中的每一个元素就是一个配置项,每一个配置项都调用url函数(高版本使用path、re_path函数)

url匹配过程:

image

注意:

  1. 匹配成功调用视图函数产生内容返回客户端,匹配失败产生404异常
  2. 不能在开始加反斜杠,推荐在结束加反斜杠

内置错误视图

404:找不到页面(请求的URL没有配置或者配置错误)
- 关闭调试模式之后,默认会显示一个标准的错误页面,如果要显示自定义的页面,则需要的templates目录下面自定义一个404.html文件
- 默认情况下Django会向404.html文件传递一个参数:request_path(请求的路径)

500:服务器端错误(视图函数内部执行出错)
- 默认会显示一个标准的500服务器错误页面,如果要显示自定义的页面,则需要的templates目录下面自定义一个500.html文件

一般情况下,在网站开发完毕后需要进行以下操作:修改项目配置文件

  • 关闭调试模式:DEBUG = False
  • 允许所有ip访问:ALLOWED_HOST=[ ‘*’]

URL参数捕获

如果我们要使用URL传递的参数就需要对URL中的参数进行捕获,具体操作:将目标值部分设置为一个正则表达式的分组

这样django框架就会自动把匹配成功后相应组的内容作为参数传递给对应的视图函数

1. 位置参数:直接使用分组()即可(一般适用于一个参数的传递)
2. 关键字参数:命名分组 r'?P<组名>xxx'
    注意:关键字参数,视图函数接收的参数名需要和分组的名字相同

2. HttpRequest对象和HttpResponse对象

2.1 HttpRequest对象

服务器接收到http协议的请求后,会根据报文创建HttpRequest对象,这个对象由Django框架自动创建,视图函数的第一个参数必须是HttpRequest对象。

视图函数必须接受一个参数request,其具体信息如下:

  • request是一个HttpRequest对象
  • request包含浏览器请求提交的信息

表单提交常用方式:

  • get:提交的参数在浏览器URL地址栏中可见(不安全)
  • post:提交的参数在请求体中,被简单加密(较安全)

注意:

  1. Django模板中表单post提交需要设置{% csrf_token %},不然会提交失败
  2. 或者把项目配置文件内 MIDDLEWARE_CLASSES项的csrf注释掉

HttpRequest对象相关属性:

1. path:字符串,表示请求的页面的完整路径,不包含域名和参数部分
2. method:字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。
    - 在浏览器中给出地址发出请求采用get方式,如超链接。
    - 在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求
3. encoding:字符串,表示提交的数据的编码方式。
    - 如果为None则表示使用浏览器的默认设置,一般为utf-8。
    - 此属性可修改,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
4. GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数(使用标签的name属性作为键、查询字符串的键)
5. POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数
6. FILES:类似于字典的对象,包含所有的上传文件
7. COOKIES:标准的Python字典,包含所有的cookie,键和值都为字符串
8. session:既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话支持时才可用,详细内容见"状态保持"

QueryDict对象

1. QueryDict对象使用django.http.QueryDict类定义,HttpRequest对象的GET、POST属性都是QueryDict类型的对象
2. 与python字典不同,QueryDict类型的对象可用来处理同一个键带有多个值的情况:
    - []或者get()方法:根据键获取值
        - 如果一个键同时拥有多个值将获取最后一个值
        - 如果键不存在则返回None值,可以设置默认值进行后续处理
    - getlist()方法:
        - 根据键获取值,多个值以列表返回,可以获取指定键的所有值
        - 如果键不存在则返回空列表[],可以设置默认值进行后续处理

GET属性

请求格式:请求地址结尾使用?,之后以"键=值"的格式拼接,多个键值对之间以&连接。

http://www.itcast.cn/?a=10&b=20&c=python

请求参数:a=10&b=20&c=python
请求参数中,键为'a'、'b'、'c',值为'10'、'20'、'python'

在Django中可以使用HttpRequest对象的GET属性获取以get方式请求提交的参数
    - 键是开发人员在编写代码时确定下来的(模板内部标签name属性)
    - 值是根据数据生成的

POST属性

使用form表单请求时,method方式为post则会发起post方式的请求,需要使用HttpRequest对象的POST属性获取提交的参数。

问:表单form如何提交参数呢?

答:表单控件name属性的值作为键,value属性的值为值,构成键值对提交
    - 如果表单控件没有name属性则不提交
    - 对于checkbox控件,name属性的值相同为一组,被选中的项会被提交,出现一键多值的情况
    - 键是表单控件name属性的值,是由开发人员编写的。
    - 值是用户填写或选择的。

2.2 HttpResponse对象

视图函数在接收请求并处理后,必须返回HttpResponse对象或其子对象。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。

HttpResponse对象相关属性与方法:

1. 属性:
    content:表示返回的内容
    charset:表示response采用的编码字符集,默认为utf-8
    status_code:返回的HTTP响应状态码
    content-type:指定返回数据的的MIME类型,默认为'text/html'
2. 方法:
    set_cookie:设置Cookie信息
        set_cookie(key, value='', max_age=None, expires=None)
    delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生
    write:向响应体中写数据

cookie是网站以键值对格式存储在浏览器中的一段纯文本信息,用于实现用户跟踪:

  • max_age是一个整数,表示在指定秒数后过期(过期时间)
  • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期
  • max_age与expires二选一
  • 如果不指定过期时间,在关闭浏览器时cookie会过期
from datetime import datetime. timedelta
response.set_cookie('num', 1, expires=datetime.now()+timedelta(days=14))

注意:render()函数也返回HttpResponse对象

子类JsonResponse对象

  • 在浏览器中使用javascript发起ajax请求时,一般会返回json格式的数据
  • JsonResponse类继承自HttpResponse类,被定义在django.http模块中,创建对象时接收字典作为参数
  • JsonResponse对象的content-type为’application/json’
Ajax:异步的javascript
- 在不重新加载整个页面的情况下对页面进行的局部刷新,ajax请求都在后台进行(比如表单内容较多的全部刷新会导致用户体验不好)
- ajax请求执行过程:
    1. 发起ajax请求:由jquery发起
    2. 服务器端执行相应的视图函数,返回json内容
    3. 执行相应的回调函数,通过判断json内容,进行相应处理
- 使用时:
    1. 首先分析出请求地址时需要携带的参数
    2. 确定视图函数处理完成之后,所返回的json数据格式

    
Django项目静态文件目录配置:
    - 在项目目录下创建static目录
    - 项目配置文件内添加STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

Ajax请求代码格式:

$.ajax({
        'url': '/books/ajax_handle/',  // ajax请求url(对应一个视图函数)
        'type': 'get',  // 请求方式(get、post)
        'dataType': 'json',  // 返回的数据格式
        'data': {}  // 请求携带的参数
        'async': false  // 同步的ajax请求(默认为异步的)
    }).success(function (data) {
        // 进行处理
        // 请求处理成功后调用的回调函数
    })

Jquery发起Ajax请求示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax请求</title>
    <script src="/static/js/jquery-1.12.4.min.js"></script>
    <script>
        $(function () {
            // 绑定按钮的点击事件
            $('#btn').click(function () {
                // 1. 获取用户名和密码
                var username = $('#username').val();
                var password = $('#password').val();
                // 2. 发起post ajax请求(携带用户名密码)
                $.ajax({
                    'url': '/books/login_ajax_check/',
                    'type': 'post',
                    'data': {
                        'username': username,
                        'password': password
                    },
                    'dataType': 'json'
                }).success(function (data) {
                    // 登录失败 {'res': 0}
                    if (data.res  === 0){
                        $('#message').show().html('用户名或密码错误!')
                    } else {
                        // 登录成功 {'res': 1}
                        location.href = '/books/index/'
                    }
                })
            })
        })
    </script>
    <style>
        #message {
            {#默认不显示,登录失败显示#}
            display: none;
            color: red;
        }
    </style>
</head>
<body>
<div>
    用户名:<input type="text" id="username"><br>
    密&nbsp;&nbsp;码:<input type="password" id="password"><br>

    <input type="button" value="登录" id="btn">
    <div id="message"></div>
</div>
</body>
</html>

ajax请求处理函数:

def login_ajax_check(request):
    """ajax登录校验"""
    # 1. 获取输入的用户名密码
    username = request.POST.get('username')
    password = request.POST.get('password')

    # 2. 校验(实际开发用户名密码存储在数据库中)
    if username == 'yuxi' and password == '123':
        # 数据正确:跳转首页(返回的json数据:{'res': 1})
        context = {
            'res': 1
        }
        return JsonResponse(context)
    else:
        # 数据错误:显示提示信息(返回的json数据:{'res': 1})
        context = {
            'res': 0
        }
        return JsonResponse(context)

3. 状态保持

http协议是无状态的,无状态指每次用户请求时,服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。

根本原因是:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。

实现状态保持主要有两种方式:

  • 在客户端存储信息使用Cookie
  • 在服务器端存储信息使用Session

3.1 cookie

Cookie指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。

Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。

Cookie名称和值可以由服务器端自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。

cookie的特点:

  • cookie以键值对方式进行存储信息
  • 通过浏览器访问一个网站时,会将浏览器存储的跟网站相关的所有cookie信息发送给该网站的服务器(视图函数中通过request.COOKIES获取)
  • cookie基于域名安全,不同域名的Cookie是不能互相访问的
  • cookie是有过期时间的,如果不指定,默认关闭浏览器之后cookie就会过期

cookie的典型应用:记住用户名、精准广告推送

cookie的使用流程

image

cookie记住用户名案例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="/books/login_check/" method="post" name="login">

    {% csrf_token %}

    用户名:<input type="text" name="username" id="user" value="{{ username }}"><br>
    密&nbsp;&nbsp;&nbsp;码:<input type="password" name="password" id="password"><br>
    记住用户名:<input type="checkbox" name="remember"><br>

    <input type="submit" value="登录">
</form>
</body>
</html>

def login(request):
    """登录页面"""
    # 获取cookie是否携带应户名信息
    if 'username' in request.COOKIES:
        username = request.COOKIES['username']
    else:
        username = ''

    context = {
        'username': username
    }

    return render(request, 'books/login.html', context)


def login_check(request):
    """登录校验"""
    # 1. 获取输入的用户名密码
    username = request.POST.get('username')
    password = request.POST.get('password')
    remember = request.POST.get('remember')
    print(remember)

    # 2. 校验(实际开发用户名密码存储在数据库中)
    if username == 'yuxi' and password == '123':
        # 数据正确:跳转首页
        response = redirect('/books/index/')
        # 勾选记住用户名,则设置cookie及过期时间
        if remember == 'on':
            response.set_cookie('username', username, max_age=7*24*3600)

        return response
    else:
        # 数据错误:回到登录页
        return redirect('/books/login/')

3.2 session

对于敏感、重要的信息,建议要储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息。

在服务器端进行状态保持的方案就是Session

session的特点:

  • session是以键值对进行存储的
  • session依赖于cookie,唯一标识码保存在cookie中(键为sessionid对用django_session表中的session_key)
  • session也是有过期时间,如果不指定,默认两周就会过期(指的是存储session的唯一标识cookie会过期)
所有请求者的Session都会存储在服务器中,服务器如何区分请求者和Session数据的对应关系呢?

答:在使用Session后,会在Cookie中存储一个sessionid的数据,每次请求时浏览器都会将这个数据发给服务器,服务器在接收到sessionid后,会根据这个值找出这个请求者的Session。

结果:如果想使用Session,浏览器必须支持Cookie,否则无法使用Session。

存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置。
Django session设置:
- 默认启用session
- 禁用session:项目配置文件中间件选项的session项删除或注释即可

设置SESSION_ENGINE项指定Session数据存储的方式指定session的存储方式:数据库、缓存、Redis等
- 存储在数据库:SESSION_ENGINE='django.contrib.sessions.backends.db'(默认)
- 存储在缓存:SESSION_ENGINE='django.contrib.sessions.backends.cache'(存储在本机内存中,如果丢失则不能找回,读写更快)
- 混合存储:SESSION_ENGINE='django.contrib.sessions.backends.cached_db'(优先从本机内存中存取,如果没有则从数据库中存取)

注意:
1. 如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用(默认已安装)
2. 数据迁移后默认生成django_session表用来存储session信息

Django session操作:通过HttpRequest对象的session属性进行会话的读写操作
    - 键值对格式读写session:request.session['键']=值
    - 根据键取值:request.session.get('键',默认值)
    - 清除所有session,在存储中删除值部分:request.session.clear()
    - 清除session数据,在存储中删除session的整条数据:request.session.flush()
    - 删除session中的指定键及值,在存储中只删除某个键及对应的值:del request.session['键']
    - 设置会话超时时间,如果没有指定过期时间则两个星期后过期:request.session.set_expiry(value)
        - 如果value是一个整数,会话的cookie sessionid将在value秒没有活动后过期
        - 如果value为0,那么用户会话的Cookie sessionid将在用户的浏览器关闭时过期
        - 如果value为None,那么会话的Cookie sessionid永不过期
    - 判断session中是否有某个key:request.session.has_key('key')

session的流程

image

注意:

  1. cookie:记住用户名,安全性要求不高。
  2. session:涉及到安全性要求比较高的数据(银行卡账户,密码)
session记住用户登录状态案例:
def login(request):
    """登录页面"""
    # 先判断用户是否登录
    if request.session.has_key('isLogin'):
        # 之前已登录,跳转到首页
        return redirect('/books/index/')
    else:
        # 用户未登录
        # 获取cookie是否携带应户名信息
        if 'username' in request.COOKIES:
            username = request.COOKIES['username']
        else:
            username = ''

        context = {
            'username': username
        }

        return render(request, 'books/login.html', context)


def login_check(request):
    """登录校验"""
    # 1. 获取输入的用户名密码
    username = request.POST.get('username')
    password = request.POST.get('password')
    remember = request.POST.get('remember')
    print(remember)

    # 2. 校验(实际开发用户名密码存储在数据库中)
    if username == 'yuxi' and password == '123':
        # 数据正确:跳转首页
        response = redirect('/books/index/')
        # 勾选记住用户名,则设置cookie及过期时间
        if remember == 'on':
            response.set_cookie('username', username, max_age=7*24*3600)

        # 记住用户登录状态(如果用户登录时session中isLogin为True则直接跳转登录页面)
        request.session['isLogin'] = True

        return response
    else:
        # 数据错误:回到登录页
        return redirect('/books/login/')
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!