zoukankan      html  css  js  c++  java
  • Django之视图Views

    视图

    • 视图接受Web请求并且返回Web响应
    • 视图就是一个python函数,被定义在views.py中
    • 响应可以是一张网页的HTML内容一个重定向一个404错误等等
    • 响应处理过程如下图:

      URLconf

    • 在settings.py文件中通过ROOT_URLCONF指定根级url的配置
    • urlpatterns是一个url()实例的列表
    • 一个url()对象包括:
    • 正则表达式
    • 视图函数
    • 名称name
    • 编写URLconf的注意:
    • 若要从url中捕获一个值,需要在它周围设置一对圆括号
    • 不需要添加一个前导的反斜杠,如应该写作'test/',而不应该写作'/test/'
    • 每个正则表达式前面的r表示字符串不转义
    • 请求的url被看做是一个普通的python字符串,进行匹配时不包括get或post请求的参数及域名
      http://www.baidu.cn/python/1/?i=1&p=new,只匹配“/python/1/”部分
    • 正则表达式非命名组,通过位置参数传递给视图
      url(r'^([0-9]+)/$', views.detail, name='detail'),
    • 正则表达式命名组,通过关键字参数传递给视图,本例中关键字参数为id
      url(r'^(?P<id>[0-9]+)/$', views.detail, name='detail'),
    • 参数匹配规则:优先使用命名参数,如果没有命名参数则使用位置参数
    • 每个捕获的参数都作为一个普通的python字符串传递给视图
    • 性能:urlpatterns中的每个正则表达式在第一次访问它们时被编译,这使得系统相当快

      包含其它的URLconfs

    • 在应用中创建urls.py文件,定义本应用中的urlconf,再在项目的settings中使用include()
      from django.conf.urls import include, url
      urlpatterns = [
          url(r'^', include('booktest.urls', namespace='booktest')),
      ]
    • 匹配过程:先与主URLconf匹配,成功后再用剩余的部分与应用中的URLconf匹配
      请求http://www.baidu.cn/booktest/1/
      在sesstings.py中的配置:
      url(r'^booktest/', include('booktest.urls', namespace='booktest')),
      在booktest应用urls.py中的配置
      url(r'^([0-9]+)/$', views.detail, name='detail'),
      匹配部分是:/booktest/1/
      匹配过程:在settings.py中与“booktest/”成功,再用“1/”与booktest应用的urls匹配
    • 使用include可以去除urlconf的冗余
    • 参数:视图会收到来自父URLconf、当前URLconf捕获的所有参数
    • 在include中通过namespace定义命名空间,用于反解析
      URL的反向解析
      如果在视图、模板中使用硬编码的链接,在urlconf发生改变时,维护是一件非常麻烦的事情
      解决:在做链接时,通过指向urlconf的名称,动态生成链接地址
      视图:使用django.core.urlresolvers.reverse()函数
      模板:使用url模板标签

      定义视图

    • 本质就是一个函数
    • 视图的参数
      • 一个HttpRequest实例
      • 通过正则表达式组获取的位置参数
      • 通过正则表达式组获得的关键字参数
    • 在应用目录下默认有views.py文件,一般视图都定义在这个文件中
    • 如果处理功能过多,可以将函数定义到不同的py文件中
      新建views1.py
      #coding:utf-8
      from django.http import HttpResponse
      def index(request):
          return HttpResponse("你好")
      
      在urls.py中修改配置
      from . import views1
      url(r'^$', views1.index, name='index'),

      错误视图

    • Django原生自带几个默认视图用于处理HTTP错误
    • 404 (page not found) 视图

    • defaults.page_not_found(request, template_name='404.html')
    • 默认的404视图将传递一个变量给模板:request_path,它是导致错误的URL
    • 如果Django在检测URLconf中的每个正则表达式后没有找到匹配的内容也将调用404视图
    • 如果在settings中DEBUG设置为True,那么将永远不会调用404视图,而是显示URLconf 并带有一些调试信息
    • 在templates中创建404.html
      <!DOCTYPE html>
      <html>
      <head>
          <title></title>
      </head>
      <body>
      找不到了
      <hr/>
      {{request_path}}
      </body>
      </html>
    • 在settings.py中修改调试
      DEBUG = False
      ALLOWED_HOSTS = ['*', ]
    • 请求一个不存在的地址
      http://127.0.0.1:8000/test/

      500 (server error) 视图

    • defaults.server_error(request, template_name='500.html')
    • 在视图代码中出现运行时错误
    • 默认的500视图不会传递变量给500.html模板
    • 如果在settings中DEBUG设置为True,那么将永远不会调用505视图,而是显示URLconf 并带有一些调试信息

              400 (bad request) 视图

    • defaults.bad_request(request, template_name='400.html')
    • 错误来自客户端的操作
    • 当用户进行的操作在安全方面可疑的时候,例如篡改会话cookie

      HttpReqeust对象

    • 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象
    • 视图函数的第一个参数是HttpRequest对象
    • 在django.http模块中定义了HttpRequest对象的API
    • 属性

    • 下面除非特别说明,属性都是只读的
    • path:一个字符串,表示请求的页面的完整路径,不包含域名
    • method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'
    • encoding:一个字符串,表示提交的数据的编码方式
    • 如果为None则表示使用浏览器的默认设置,一般为utf-8
    • 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值
    • GET:一个类似于字典的对象,包含get请求方式的所有参数
    • POST:一个类似于字典的对象,包含post请求方式的所有参数
    • FILES:一个类似于字典的对象,包含所有的上传文件
    • COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串
    • session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见“状态保持”
    • 方法

    • is_ajax():如果请求是通过XMLHttpRequest发起的,则返回True

      QueryDict对象

    • 定义在django.http.QueryDict
    • request对象的属性GET、POST都是QueryDict类型的对象
    • 与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
    • 方法get():根据键获取值
        • 只能获取键的一个值
        • 如果一个键同时拥有多个值,获取最后一个值
    dict.get('',default)
    或简写为
    dict['']

      方法getlist():根据键获取值

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

    GET属性

    • QueryDict类型的对象
    • 包含get请求方式的所有参数
    • 与url请求地址中的参数对应,位于?后面
    • 参数的格式是键值对,如key1=value1
    • 多个参数之间,使用&连接,如key1=value1&key2=value2
    • 键是开发人员定下来的,值是可变的
    • 示例如下
    • 创建视图getTest1用于定义链接,getTest2用于接收一键一值,getTest3用于接收一键多值
      def getTest1(request):
          return render(request,'booktest/getTest1.html')
      def getTest2(request):
          return render(request,'booktest/getTest2.html')
      def getTest3(request):
          return render(request,'booktest/getTest3.html')
    • 配置url
      url(r'^getTest1/$', views.getTest1),
      url(r'^getTest2/$', views.getTest2),
      url(r'^getTest3/$', views.getTest3),
    • 创建getTest1.html,定义链接
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      链接1:一个键传递一个值
      <a href="/getTest2/?a=1&b=2">gettest2</a><br>
      链接2:一个键传递多个值
      <a href="/getTest3/?a=1&a=2&b=3">gettest3</a>
      </body>
      </html>
    • 完善视图getTest2的代码
      def getTest2(request):
          a=request.GET['a']
          b=request.GET['b']
          context={'a':a,'b':b}
          return render(request,'booktest/getTest2.html',context)
    • 创建getTest2.html,显示接收结果
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      a:{{ a }}<br>
      b:{{ b }}
      </body>
      </html>
    • 完善视图getTest3的代码
      def getTest3(request):
          a=request.GET.getlist('a')
          b=request.GET['b']
          context={'a':a,'b':b}
          return render(request,'booktest/getTest3.html',context)
    • 创建getTest3.html,显示接收结果
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      a:{% for item in a %}
      {{ item }}
      {% endfor %}
      <br>
      b:{{ b }}
      </body>
      </html>

      POST属性

    • QueryDict类型的对象
    • 包含post请求方式的所有参数
    • 与form表单中的控件对应
    • 问:表单中哪些控件会被提交?
    • 答:控件要有name属性,则name属性的值为键,value属性的值为键,构成键值对提交
    • 对于checkbox控件,name属性一样为一组,当控件被选中后会被提交,存在一键多值的情况
    • 键是开发人员定下来的,值是可变的
    • 示例如下
    • 定义视图postTest1
      def postTest1(request):
          return render(request,'booktest/postTest1.html')
    • 配置url
      url(r'^postTest1$',views.postTest1)
    • 创建模板postTest1.html
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      <form method="post" action="/postTest2/">
          姓名:<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="胸口碎大石"/>胸口碎大石
          <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接收请求的数据
      def postTest2(request):
          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)
    • 配置url
      url(r'^postTest2$',views.postTest2)
    • 创建模板postTest2.html
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      {{ uname }}<br>
      {{ upwd }}<br>
      {{ ugender }}<br>
      {{ uhobby }}
      </body>
      </html>
    • 注意:使用表单提交,注释掉settings.py中的中间件crsf

      HttpResponse对象

    • 在django.http模块中定义了HttpResponse对象的API
    • HttpRequest对象由Django自动创建,HttpResponse对象由程序员创建
    • 不调用模板,直接返回数据
    #coding=utf-8
    from django.http import HttpResponse
    
    def index(request):
        return HttpResponse('你好')
    • 调用模板
      from django.http import HttpResponse
      from django.template import RequestContext, loader
      
      def index(request):
          t1 = loader.get_template('polls/index.html')
          context = RequestContext(request, {'h1': 'hello'})
          return HttpResponse(t1.render(context))

      属性

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

    • 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二选一
      • 如果不指定过期时间,则两个星期后过期
        from django.http import HttpResponse
        from datetime import *
        
        def index(request):
            response = HttpResponse()
            if request.COOKIES.has_key('h1'):
                response.write('<h1>' + request.COOKIES['h1'] + '</h1>')
            response.set_cookie('h1', '你好', 120)
            # response.set_cookie('h1', '你好', None, datetime(2016, 10, 31))
            return response

     

    • delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生

      子类HttpResponseRedirect

    • 重定向,服务器端跳转
    • 构造函数的第一个参数用来指定重定向的地址
      在views1.py中
      from django.http import HttpResponse,HttpResponseRedirect
      def index(request):
          return HttpResponseRedirect('js/')
      def index2(request,id):
          return HttpResponse(id)
      
      在应用的urls.py中增加一个url对象
      url(r'^([0-9]+)/$', views1.index2, name='index2'),
    • 请求地址栏如图:

          

    • 请求结果的地址栏如图:

          

    • 推荐使用反向解析
      from django.core.urlresolvers import reverse
      
      def index(request):
          return HttpResponseRedirect(reverse('booktest:index2', args=(1,)))

      子类JsonResponse

    • 返回json数据,一般用于异步请求
    • _init _(data)
    • 帮助用户创建JSON编码的响应
    • 参数data是字典对象
    • JsonResponse的默认Content-Type为application/json
      from django.http import JsonResponse
      
      def index2(requeset):
          return JsonResponse({'list': 'abc'})

      简写函数

      render

    • render(request, template_name[, context])
    • 结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象
    • request:该request用于生成response
    • template_name:要使用的模板的完整名称
    • context:添加到模板上下文的一个字典,视图将在渲染模板之前调用它
      from django.shortcuts import render
      
      def index(request):
          return render(request, 'booktest/index.html', {'h1': 'hello'})

      重定向

    • redirect(to)
    • 为传递进来的参数返回HttpResponseRedirect
    • to推荐使用反向解析

         

    from django.shortcuts import redirect
    from django.core.urlresolvers import reverse
    
    def index(request):
        return redirect(reverse('booktest:index2'))

        得到对象或返回404

    • get_object_or_404(klass, args, *kwargs)
    • 通过模型管理器或查询集调用get()方法,如果没找到对象,不引发模型的DoesNotExist异常,而是引发Http404异常
    • klass:获取对象的模型类、Manager对象或QuerySet对象
    • **kwargs:查询的参数,格式应该可以被get()和filter()接受
    • 如果找到多个对象将引发MultipleObjectsReturned异常
      from django.shortcuts import *
      
      def detail(request, id):
          try:
              book = get_object_or_404(BookInfo, pk=id)
          except BookInfo.MultipleObjectsReturned:
              book = None
          return render(request, 'booktest/detail.html', {'book': book})
      
      将settings.py中的DEBUG改为False
      将请求地址输入2和100查看效果

      得到列表或返回404

    • get_list_or_404(klass, args, *kwargs)
    • klass:获取列表的一个Model、Manager或QuerySet实例
    • **kwargs:查寻的参数,格式应该可以被get()和filter()接受
    from django.shortcuts import *
    
    def index(request):
        # list = get_list_or_404(BookInfo, pk__lt=1)
        list = get_list_or_404(BookInfo, pk__lt=6)
        return render(request, 'booktest/index.html', {'list': list})
    
    将settings.py中的DEBUG改为False

    状态保持

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

    启用session

    • 使用django-admin startproject创建的项目默认启用
    • 在settings.py文件中
      项INSTALLED_APPS列表中添加:
      'django.contrib.sessions',
      
      项MIDDLEWARE_CLASSES列表中添加:
      'django.contrib.sessions.middleware.SessionMiddleware',
    • 禁用会话:删除上面指定的两个值,禁用会话将节省一些性能消耗

    使用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.core.urlresolvers import reverse
      
      def index(request):
          uname = request.session.get('uname')
          return render(request, 'booktest/index.html', {'uname': uname})
      
      def login(request):
          return render(request, 'booktest/login.html')
      
      def login_handle(request):
          request.session['uname'] = request.POST['uname']
          return redirect(reverse('main:index'))
      
      def logout(request):
          # request.session['uname'] = None
          # del request.session['uname']
          # request.session.clear()
          request.session.flush()
          return redirect(reverse('main:index'))
    • 配置url
      主url:
      from django.conf.urls import include, url
      urlpatterns = [
          url(r'^', include('booktest.urls', namespace='main'))
      ]
      
      应用url:
      from django.conf.urls import url
      from . import views
      urlpatterns = [
          url(r'^$', views.index, name='index'),
          url(r'login/$', views.login, name='login'),
          url(r'login_handle/$', views.login_handle, name='login_handle'),
          url(r'logout/$', views.logout, name='logout')
      ]
    • 创建模板index.html
      <!DOCTYPE html>
      <html>
      <head>
          <title>首页</title>
      </head>
      <body>
      你好:{{uname}}
      <hr/>
      <a href="{%url 'main:login'%}">登录</a>
      <hr/>
      <a href="{%url 'main:logout'%}">退出</a>
      </body>
      </html>
    • 创建模板login.html
      <!DOCTYPE html>
      <html>
      <head>
          <title>登录</title>
      </head>
      <body>
      <form method="post" action="/login_handle/">
          <input type="text" name="uname"/>
          <input type="submit" value="登录"/>
      </form>
      </body>
      </html>

      会话过期时间

    • set_expiry(value):设置会话的超时时间
    • 如果没有指定,则两个星期后过期
    • 如果value是一个整数,会话将在values秒没有活动后过期
    • 若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
    • 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
    • 如果value为None,那么会话永不过期
    • 修改视图中login_handle函数,查看效果
      def login_handle(request):
          request.session['uname'] = request.POST['uname']
          # request.session.set_expiry(10)
          # request.session.set_expiry(timedelta(days=5))
          # request.session.set_expiry(0)
          # request.session.set_expiry(None)
          return redirect(reverse('main:index'))

      存储session

    • 使用存储会话的方式,可以使用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'

      使用Redis缓存session

    • 会话还支持文件、纯cookie、Memcached、Redis等方式存储,下面演示使用redis存储
    • 安装包
      pip install django-redis-sessions
    • 修改settings中的配置,增加如下项
      SESSION_ENGINE = 'redis_sessions.session'
      SESSION_REDIS_HOST = 'localhost'
      SESSION_REDIS_PORT = 6379
      SESSION_REDIS_DB = 0
      SESSION_REDIS_PASSWORD = ''
      SESSION_REDIS_PREFIX = 'session'
    • 管理redis的命令
      启动:sudo redis-server /etc/redis/redis.conf
      停止:sudo redis-server stop
      重启:sudo redis-server restart
      redis-cli:使用客户端连接服务器
      keys *:查看所有的键
      get name:获取指定键的值
      del name:删除指定名称的键
  • 相关阅读:
    20155313 杨瀚 《网络对抗技术》实验九 Web安全基础
    20155313 杨瀚 《网络对抗技术》实验八 Web基础
    20155313 杨瀚 《网络对抗技术》实验七 网络欺诈防范
    20155313 杨瀚 《网络对抗技术》实验六 信息搜集与漏洞扫描
    20155313 杨瀚 《网络对抗技术》实验五 MSF基础应用
    20155313 杨瀚 《网络对抗技术》实验四 恶意代码分析
    20155313 杨瀚 《网络对抗技术》实验三 免杀原理与实践
    20155313 杨瀚 《网络对抗技术》实验二 后门原理与实践
    20155313 杨瀚 《网络对抗技术》实验一 PC平台逆向破解(5)M
    20155313 2017-2018-1 《信息安全系统设计基础》课程总结
  • 原文地址:https://www.cnblogs.com/alexzhang92/p/9314474.html
Copyright © 2011-2022 走看看