zoukankan      html  css  js  c++  java
  • <Django> MVT三大块之view(视图)

    1.视图简介

      作用:接受web请求,返回web响应

      本质:一个函数,定义在views.py文件中(定义在其他地方也行,约定俗成)

      流程:(如果匹配不到,报一个404错误)-----结果返回http response对象

    1.1 视图配置

      在settings.py文件的ROOT_URLCONF部分指定根级url的配置(指向urls.py文件)

    查找流程,mannage.py→settings.py→urls.py

    习惯上,每个应用(APP)单独配置自己的urls.py,不写在根目录,防止因为应用过多,看起来太混乱不好维护,

    配置自己的url:只需创建应用后在应用文件中创建urls.py文件(在根目录中包含)

    1.2 简单的演示

    根目录下的urls.py文件

    from django.conf.urls import url, include
    from django.contrib import admin
    
    urlpatterns = [
    	url(r'^admin/', admin.site.urls),
    	url(r'^booktest/', include('booktest.urls')),
    ] 

    app目录下的url.py文件

    from django.conf.urls import url
    from booktest import views
    urlpatterns = [
    	url(r'^$',views.index),
    ]

    views.py文件

    from django.http import HttpResponse
    # Create your views here.
    def index(request):
    	return  HttpResponse("Hello World!")

    启动django

    python manage.py runserver

    访问网址

     

    1.3 匹配规则

      第一步:去掉域名和端口号

      第二步:在根目录下匹配(匹配成功,进入include)

      第三步:去掉根目录里面已经匹配成功的,继续在APP中urls.py匹配(匹配成功,执行对应views.py中的函数)

      第四步:执行view.py中的函数

      匹配的时候,可以利用正则中的()可以保留匹配的内容,形如:(d+)

    1.4  urlconf 

    #正则表达式非命名组,通过位置参数传递给视图
    url(r'^([0-9]+)/$', views.detail, name='detail'),
    
    #正则表达式命名组,通过关键字参数传递给视图,本例中关键字参数为id
    url(r'^(?P<id>[0-9]+)/$', views.detail, name='detail'),
    • 参数匹配规则:优先使用关键字(命名)参数,如果没有命名参数则使用位置参数
    • 每个捕获的参数都作为一个普通的python字符串传递给视图
    • 性能:urlpatterns中的每个正则表达式在第一次访问它们时被编译,这使得系统相当快
    # namespace跟url里面的name一样,起名字用于反向解析
    url(r'^', include('booktest.urls', namespace='booktest')),

    1.5 反向解析(之后在写)

    • 如果在视图、模板中使用硬编码的链接,在urlconf发生改变时,维护是一件非常麻烦的事情
    • 解决:在做链接时,通过指向urlconf的名称,动态生成链接地址
    • 视图:使用django.core.urlresolvers.reverse()函数
    • 模板:使用url模板标签

    2. 视图函数

    2.1 基本视图

      调用,views内对应的函数即可,

    2.2 错误视图(404未找到,500服务器未响应,400错误来自客户端)

      Django原生自带几个默认视图用于处理HTTP错误

      第一步:项目目录下,添加templates文件夹

      第二步:settings.py 中添加模板路径

      第三步:在templates中创建404.html(调试状态下,看不到这页面)

      settings.py 设置DEBUG为False

      设置允许谁请求主机

      

    404.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
    <h1>找不到,404</h1>
    {{ request_path}}}
    </body>
    </html>

    启动,错误的访问的结果为:

    3. Reqeust对象(接收的对象)

      在django.http模块中定义了HttpRequest对象的API

    3.1 属性

      下面除非特别说明,属性都是只读的

      path:一个字符串,表示请求的页面的完整路径,不包含域名

    def index(request):
    	return  HttpResponse(request.path)
    

      

      method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'

      encoding:一个字符串,表示提交的数据的编码方式

        如果为None则表示使用浏览器的默认设置,一般为utf-8

        这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值

      GET:一个类似于字典的对象,包含get请求方式的所有参数

      POST:一个类似于字典的对象,包含post请求方式的所有参数

      FILES:一个类似于字典的对象,包含所有的上传文件

      COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串

      session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见“状态保持”

      这些属性的用法类似

    from django.http import HttpResponse
    # Create your views here.
    def index(request):
    	return HttpResponse(
    		# request.path,
    		# request.method,
    		# request.encoding,
    		request.GET,
    		# request.POST,
    		# request.FILES,
    		# request.COOKIES,
    		# request.session,
    	)
    

      

    3.2  类似字典对象(QueryDict对象)

      字典:键值对,键不能相同

      QueryDict:键值对,键能相同,如果同一键有多个值,获取最后一个值

      get():根据键获取值,类字典

    dict.get('键',default)
    #或简写为
    dict['键']
    

      getlist():根据键获取多个值

    #将键的值以列表返回,可以获取一个键的多个值
    dict.getlist('键',default)

    3.3 GET属性 

    • QueryDict类型的对象
    • 包含get请求方式的所有参数
    • 与url请求地址中的参数对应,位于?后面
    • 参数的格式是键值对,如key1=value1
    • 多个参数之间,使用&连接,如key1=value1&key2=value2
    • 键是开发人员定下来的,值是可变的

    对应三种视图getTest1用于定义链接,getTest2用于接收一键一值,getTest3用于接收一键多值

    views.py

    from django.shortcuts import render
    
    # Create your views here.
    # 展示链接的页面
    def getTest1(request):
    	return render(request, 'booktest/getTest1.html')
    
    
    # 接收一键一值的情况
    def getTest2(request):
    	# request.GET.get('a')
    	# 根据键接收值
    	a1 = request.GET['a']
    	b1 = request.GET['b']
    	c1 = request.GET['c']
    	# 构造上下文
    	context = {'a':a1,'b':b1,'c':c1}
    	# 向模板传递上下文,并渲染
    	return render(request, 'booktest/getTest2.html', context=context)
    
    
    # 接收一键多值的情况
    def getTest3(request):
    	# 得到最后一个
    	a1 = request.GET['a']
    	# 得到多个
    	a2 = request.GET.getlist('a')
    	c1 = request.GET['c']
    	contest = {'a':a1,'a1':a2,'c':c1}
    	return render(request, 'booktest/getTest3.html',context=contest)
    

      

    配置urls.py(APP里面的)

    from django.conf.urls import url
    from booktest import views
    urlpatterns = [
    	url(r'^getTest1/$',views.getTest1),
    	url(r'^getTest2/$',views.getTest2),
    	url(r'^getTest3/$',views.getTest3),
    ]
    

      

    配置模板

    getTest1.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>test1</title>
    </head>
    <body>
    一键一值:<a href="/booktest/getTest2/?a=1&b=2&c=3">test2</a>
    <hr>
    一键多值:<a href="/booktest/getTest3/?a=1&a=2&c=3">test3</a>
    </body>
    </html>
    

      效果:

    getTest2.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>test2</title>
    </head>
    <body>
    a:{{a}}
    <hr>
    b:{{b}}
    <hr>
    c:{{c}}
    </body>
    </html>
    

      效果

    getTest3.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>test3</title>
    </head>
    <body>
    a:{{a}}
    <br>
    a1:{{a1}}
    <br>
    a2:{%for item in a1 %}
    {{ item }}
    {% endfor %}
    <br>
    c:{{c}}
    
    </body>
    </html>
    

      效果

    3.4 POST属性

    • QueryDict类型的对象
    • 包含post请求方式的所有参数
    • 与form表单中的控件对应
    • 问:表单中哪些控件会被提交?
    • 答:控件要有name属性,则name属性的值为键,value属性的值为键,构成键值对提交
      • 对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况
    • 键是开发人员定下来的,值是可变的

    使用表单提交,注释掉settings.py中的中间件crsf

     views.py

    from django.shortcuts import render
    
    # Create your views here.
    
    # 提交表单
    def postTest1(request):
    	return render(request,'booktest/postTest1.html')
    # 展示提交的表单内容
    def postTest2(request):
    	# 表单的name作为键,value作为值传递过来
    	uname = request.POST['uname']
    	upwd = request.POST['upwd']
    	ugender = request.POST['ugender']
    	uhobby = request.POST.getlist('uhobby')
    	context = {'uname': uname, 'upwd': upwd, 'ugender': ugender, 'uhobby': uhobby}
    	return render(request,'booktest/postTest2.html',context=context)
    

      

    配置urls.py(APP里面的)

    from django.conf.urls import url
    from booktest import views
    urlpatterns = [
    	# url(r'^getTest1/$',views.getTest1),
    	# url(r'^getTest2/$',views.getTest2),
    	# url(r'^getTest3/$',views.getTest3),
    	url(r'^postTest1/$',views.postTest1),
    	url(r'^postTest2/$',views.postTest2),
    ]
    

      

    配置模板

    postTest1.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>postTest1</title>
    </head>
    <body>
    <form action="/booktest/postTest2/" method="post">
        姓名:<input type="text" name="uname"/><br>
        密码:<input type="password" name="upwd"/><br>
        性别:<input type="radio" name="ugender" value="1"/>男
        <input type="radio" name="ugender" value="0"/>女<br>
        爱好:<input type="checkbox" name="uhobby" value="玩LOL"/>玩LOL
        <input type="checkbox" name="uhobby" value="跳楼"/>跳楼
        <input type="checkbox" name="uhobby" value="喝酒"/>喝酒
        <input type="checkbox" name="uhobby" value="爬山"/>爬山<br>
        <input type="submit" value="提交"/>
    </form>
    </body>
    </html>
    

      效果:

    postTest2.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>postTest2</title>
    </head>
    <body>
    {{ uname }}<br>
    {{ upwd }}<br>
    {{ ugender }}<br>
    {{ uhobby }}
    </body>
    </html>
    

      效果:

    4. Response对象(发送的对象)

    4.1 属性

    • content:表示返回的内容,字符串类型
    • charset:表示response采用的编码字符集,字符串类型
    • status_code:响应的HTTP响应状态码
    • content-type:指定输出的MIME类型(解析方式)

    4.2 方法

    • init :使用页内容实例化HttpResponse对象
    • write(content):以文件的方式写
    • flush():以文件的方式输出缓存区
    • set_cookie(key, value='', max_age=None, expires=None):设置Cookie
      • key、value都是字符串类型
      • max_age是一个整数,表示在指定秒数后过期
      • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
      • max_age与expires二选一
      • 如果不指定过期时间,则两个星期后过期

    views.py

    from django.shortcuts import render
    from django.http import HttpResponse
    from datetime import *
    
    # Create your views here.
    def cookieTest(request):
    	response = HttpResponse()
    	cookie = request.COOKIES
    	if 't1' in cookie:
    		response.write(cookie['t1'])
    	response.set_cookie('t1','abcaaa')
    	return response

    urls.py

    	url(r'^cookieTest/$',views.cookieTest),
    

      效果:

    4.3 重定向

      一般作为:登录成功后,转向新的页面

      HttpResponseRedirect类继承于HttpResponse

    views.py

    from django.shortcuts import render,redirect
    from django.http import HttpResponse,HttpResponseRedirect
    
    
    
    # Create your views here.
    def redTest1(request):
    	# return HttpResponseRedirect('/booktest/redTest2/')
    	# 跟上面功能一致,也用于重定向(简写)
    	return redirect('/booktest/redTest2/')
    # 转向来的页面
    def redTest2(request):
    	return HttpResponse("这是转向来的页面")

    urls.py

    	url(r'^redTest1/$',views.redTest1),
    	url(r'^redTest2/$',views.redTest2),
    

     效果:访问:http://127.0.0.1:8000/booktest/redTest1/

     自动跳转,效果

    4.4 状态保持

    • http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
    • 客户端与服务器端的一次通信,就是一次会话
    • 实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
    • 存储方式包括cookie、session,会话一般指session对象
    • 使用cookie,所有数据存储在客户端,注意不要存储敏感信息
    • 推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储session_id
    • 状态保持的目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据
    • 注意:不同的请求者之间不会共享这个数据,与请求者一一对应

    Django默认就启用Session,不用就去settings.py中禁用

    使用Session(会存到数据库中去)

    • 启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
    • get(key, default=None):根据键获取会话的值
    • clear():清除所有会话
    • flush():删除当前的会话数据并删除会话的Cookie
    • del request.session['member_id']:删除会话

    views.py

    from django.shortcuts import render, redirect
    from django.http import HttpResponse, HttpResponseRedirect
    
    
    # Create your views here.
    # 第一个登录显示页面
    def session1(request):
    	# 键不存在,设置默认值
    	uname = request.session.get('myname','未登录')
    	context = {'uname': uname}
    	return render(request, 'booktest/session1.html', context=context)
    
    # 登录表单提交阶段
    def session2(request):
    	return render(request, 'booktest/session2.html')
    
    # 删除session,退出
    def session3(request):
    	del request.session['myname']
    	return redirect('/booktest/session1/')
    
    def session2_handle(request):
    	uname = request.POST['uname']
    	# session对象(字典) 往session对象中写对象
    	request.session['myname'] = uname
    	# 重定向,显示登录的页面
    	return redirect('/booktest/session1/')

    urls.py

    	url(r'^session1/$',views.session1),
    	url(r'^session2/$',views.session2),
    	url(r'^session2_handle/$',views.session2_handle),
    	url(r'^session3/$',views.session3),
    

      

    session1.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>login</title>
    </head>
    <body>
    <h1>你好:{{ uname }}</h1>
    <br>
    <a href="/booktest/session2/">登录</a>
    <br>
    <a href="/booktest/session3/">退出</a>
    </body>
    </html>
    

      效果:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>表单</title>
    </head>
    <body>
    <form action="/booktest/session2_handle/" method="post">
        <input type="text" name="uname">
        <input type="submit" name="登录">
    </form>
    </body>
    </html>
    

     效果:

     

    因为Session需要存到数据库:需要进行数据迁移-------这个需要运行前先迁移

    settings.py(可以用已经迁移过的数据库、表)

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'test2',
            'USER':'root',
            'PASSWORD':'',
            'HOST':'localhost',
            'POST':'3306',
        }
    }
    

      

    提交表单后效果

    点击退出后的效果(使用默认值,清楚session)

    4.5 会话

    会话过期时间

    • set_expiry(value):设置会话的超时时间
    • 如果没有指定,则两个星期后过期
    • 如果value是一个整数,会话将在values秒没有活动后过期
    • 若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
    • 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
    • 如果value为None,那么会话永不过期
    • 修改视图中session2_handle函数,查看效果
    def session2_handle(request):
    	uname = request.POST['uname']
    	# session对象(字典) 往session对象中写对象
    	request.session['myname'] = uname
    	# 设置会话过期时间
    	request.session.set_expiry(0)
    	# 重定向,显示登录的页面
    	return redirect('/booktest/session1/')  

    存储session

    数据库中的session

    base64解码--session_data

    • 使用存储会话的方式,可以使用settings.py的SESSION_ENGINE项指定
    • 基于数据库的会话:这是django默认的会话存储方式,需要添加django.contrib.sessions到的INSTALLED_APPS设置中,运行manage.py migrate在数据库中安装会话表,可显示指定为
    SESSION_ENGINE='django.contrib.sessions.backends.db'
    

      存在缓存

    SESSION_ENGINE='django.contrib.sessions.backends.cache'
    

      存在数据库+缓存

    SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

    流程

  • 相关阅读:
    python之接口与抽象类
    python之内置函数与匿名函数
    python之常用模块
    python之块包导入
    python之协程函数、递归、二分法
    Ios证书申请流程
    VUE + vue-cli + webpack 创建新项目(2)
    VUE + vue-cli + webpack 创建新项目
    布局的几种方式(静态布局、自适应布局、流式布局、响应式布局、弹性布局)
    浅谈rem布局和vm布局
  • 原文地址:https://www.cnblogs.com/shuimohei/p/10764886.html
Copyright © 2011-2022 走看看