zoukankan      html  css  js  c++  java
  • Django视图层

    Django的View(视图)


    一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。

    响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

    无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中


    FBV与CBV


    无论是FBV还是CBV路由层都是路由对应视图函数内存地址


    FBV

    基于函数的视图

    >>>> urls.py
    
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^add_press/', views.add_press),
    ]
    
    >>>> views.py
    from django.shortcuts import render, redirect
    from .models import Press, Book, Author
    
    def add_press(request):
        if request.method == 'POST':
            name = request.POST.get('name')
            Press.objects.create(name=name)
            return redirect('/press_list/')
        return render(request, 'add/add_press2.html')
    

    CBV

    基于类的视图

    >>>> urls.py
    
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^add_press/', views.AddPress.as_view()),
    ]
    
    
    >>>> views.py
    
    from django.shortcuts import render, redirect
    from django.views import View
    from .models import Press, Book, Author
    
    class AddPress(View):
        def get(self, request):
            return render(request, 'add/add_press2.html')
    
    
        def post(self, request):
            name = request.POST.get('name')
            Press.objects.create(name=name)
            return redirect('/press_list/')
    

    CBV执行流程

    1. 实例化自己写的类
    		AddPress.as_view()  --->  调用父类(View)的类绑定方法as_view并执行as_view下的嵌套函数view(主要作用是实例化对象和返回父类下的dispath方法执行的返回值)
     
        class View(object):
          @classonlymethod
          def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
              self = cls(**initkwargs)
              self.request = request
              self.args = args
              self.kwargs = kwargs
              return self.dispatch(request, *args, **kwargs)
    
            return view
    
      
    2. 执行dispatch方法
    		判断请求方式是否被允许
    			1. 允许的情况
        			handler = 通过反射获取 get  post 方法
          
    			2. 不允许的情况
    					handler = 不允许的方法
            
    			3. handler(request, *args, **kwargs)
        
      class View(object):
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
        def dispatch(self, request, *args, **kwargs):
          if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
          else:
            handler = self.http_method_not_allowed
              return handler(request, *args, **kwargs)
            
    3. 返回HttpResponse对象给到父类的as_view类绑定方法的嵌套函数view
    4. view的返回值, 即响应结果由django处理返回给浏览器进行渲染
    

    视图函数中使用装饰器


    装饰器

    import time
    
    def timer(fn):
        def inner(*args, **kwargs):
            '''执行前的操作, 计算初始时间'''
            start = time.time()
    
            '''函数执行, 并将返回值由变量ret保存'''
            ret = fn(*args, **kwargs)
    
            '''函数执行后的操作'''
            print('函数的执行时间是{}'.format(time.time() - start))
    
            '''返回函数的返回值'''
            return ret
        return inner
    

    FBV

    from django.shortcuts import render, redirect
    from django.views import View
    from .models import Press, Book, Author
    
    
    @timer
    def add_press(request):
        if request.method == 'POST':
            name = request.POST.get('name')
            Press.objects.create(name=name)
            return redirect('/press_list/')
        return render(request, 'add/add_press2.html')
    

    CBV

    from django.utils.decorators import method_decorator

    第一种方法

    在每个请求方法上分别加 @method_decorator(timer)

    from django.shortcuts import render, redirect
    from django.views import View
    from .models import Press, Book, Author
    import time
    from django.utils.decorators import method_decorator
    
    class AddPress(View):
    
        @method_decorator(timer)
        def get(self, request):
            return render(request, 'add/add_press2.html')
    
        @method_decorator(timer)
        def post(self, request):
            name = request.POST.get('name')
            Press.objects.create(name=name)
            return redirect('/press_list/')
    

    第二种方法

    想要将类中的所有方法都加上装饰器, 重写dispatch方法, 给dispatch方法加上装饰器

    from django.shortcuts import render, redirect
    from django.views import View
    from .models import Press, Book, Author
    import time
    from django.utils.decorators import method_decorator
    
    
    class AddPress(View):
    
        @method_decorator(timer)
        def dispatch(self, request, *args, **kwargs):
            ret = super().dispatch(request, *args, **kwargs)
            return ret
    
        def get(self, request):
            return render(request, 'add/add_press2.html')
    
        def post(self, request):
            name = request.POST.get('name')
            Press.objects.create(name=name)
            return redirect('/press_list/')
    

    第三种方法

    在类名上面加装饰器, 但是需要制定name属性

    from django.shortcuts import render, redirect
    from django.views import View
    from .models import Press, Book, Author
    import time
    from django.utils.decorators import method_decorator
    
    @method_decorator(timer, name='get')
    @method_decorator(timer, name='post')
    class AddPress(View):
    
        def dispatch(self, request, *args, **kwargs):
            ret = super().dispatch(request, *args, **kwargs)
            return ret
    
        def get(self, request):
            return render(request, 'add/add_press2.html')
    
        def post(self, request):
            name = request.POST.get('name')
            Press.objects.create(name=name)
            return redirect('/press_list/')
    

    Request对象和Response对象


    request对象

    当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象。
    Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。

    官方文档

    请求地址格式
    http://127.0.0.1/index  
    url:协议://IP:port/路径?get请求数据
    

    request.png


    请求相关的常用值


    假如提交的url是 http://127.0.0.1:8000/test/?id=1

    • request.path_info 返回用户访问url,不包括域名

      /test/
      

    • request.path 返回用户访问url,不包括域名

      /test/
      
    • request.method 一个字符串, 表示请求使用的HTTP方法, 例如 "GET", "POST"

      GET
      

    • request.GET 包含所有HTTP GET参数的类字典对象

      <QueryDict: {}>
      

    • request.POST 包含所有HTTP POST参数的类字典对象

      <QueryDict: {}>
      

    • request.body 请求内容,byte类型

      业务场景主要是在处理非 HTTP形式的报文时非常有用, 例如: 二进制图片, XML, Json

      request.POST的数据就是从body里面提取到的, 如果要处理表单数据的时候, 推荐还是使用 request.POST

      注意 ! ! ! 请求内容从request.POST中取到后, 这里就取不到数据了

      b''
      

    • request.FILES 一个类似字典的对象, 包含所有的上传文件信息

      注意 ! ! ! FILES 只有在请求的方法为 POST 且提交的 <form>带有 enctype="multipart/form-data"的情况下才会包含数据, 否则, FILES 将为一个空的类似于字典的对象

      <MultiValueDict: {'myfile': [<InMemoryUploadedFile: avatar.jpg (image/jpeg)>]}>
      

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

      如果为None, 则表示使用 DEFAULT_CHARSET 的设置, 默认为 'utf-8')

      这个属性是可写的, 可以修改它来修改访问表单数据使用的编码

      接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding值

      如果你知道表单数据的编码不是 DEFAULT_CHARSET, 则使用它


    • request.META 一个标准的python字典, 包含所有的HTTP 首部. 具体的头部信息取决于客户端和服务器

      键值 说明
      CONTENT_LENGTH 请求的正文的长度(是一个字符串)
      CONTENT_TYPE 请求的正文的MIME类型
      HTTP_ACCEPT 响应可接受的Content_Type
      HTTP_ACCEPT_ENCODING 响应可接收的编码
      HTTP_ACCEPT_LANGUAGE 响应可接收的语言
      HTTP_HOST 客户端发送HTTP Host头部
      HTTP_REFERER Referring 页面
      HTTP_USER_AGENT 客户端的user-agent字符串
      QUERY_STRING 单个字符串形式的查询字符串(未解析过的形式)
      REMOTE_ADDR 客户端的IP 地址
      REMOTE_HOST 客户端的主机名
      REMOTE_USER 服务器认证后的用户
      REQUEST_METHOD 一个字符串, 例如'GET' 或 'POST'
      SERVER_NAME 服务器的主机名
      SERVER_PORT 服务器d额端口(是一个字符串)

      从上面的表格可以看到, 除 CONTENT_LENGTHCONTENT_TYPE之外, 请求中任何 HTTP 首部转换为 META时, 都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_前缀

      所以, 一个叫做 X-Bender的头部将转换成 META 中的 HTTP_X_BENDER


    • request.user 用户认证组件下使用, 一个AUTH_USER_MODEL 类型的对象, 表示当前登录的用户

      如果用户当前没有登录, user将设置为 django.contrib.auth.model.AnonymousUser的一个实例, 可以通过is_authenticated区分他们

      AnonymousUser    ----> 用户没有登录时候的request.user的输出
      

    • request.COOKIES 一个标准的python字典, 包含所有的cookie. 键和值都是字符串

      {'csrftoken': 'xINH6A3h92N0jd38Jck3AhBnYp9xCZqSu7SR1AU7JP4Vmvs24Cc3hj3DYaGxhfj5'}
      

    • request.session 一个既可读又可写的类似字典的对象, 表示当前的会话. 只有当django启用会话的支持时才可用

      <django.contrib.sessions.backends.db.SessionStore object at 0x10b764ef0>
      

    • request.scheme 表示请求方案的字符串(通常为http或https)

      http
      

    请求相关的常用方法


    • request.get_full_path() 路径加参数
    /test/?id=1
    

    • request.get_host() 获取IP:port
    127.0.0.1:8000
    

    • request.get_port() 获取port

      8000
      

    • request.get_raw_uri() 获取url

      http://127.0.0.1:8000/test/?id=
      

    • request.is_secure() 判断url连接是否是受信任的链接

      False
      

    • request.is_ajax() 判断是否通过ajax提交post请求

      False
      

    Response对象


    与由Django自动创建的HttpRequest对象相比,HttpResponse对象是我们的职责范围了。我们写的每个视图都需要实例化,填充和返回一个HttpResponse。

    HttpResponse类位于django.http模块中


    from django.shortcuts import render, HttpResponse, redirect
    			1. HttpResponse    HttpResponse('字符串')   
    			2. render(request,'html文件名',{})    —— 》 HTML代码
    			3. redirect(跳转的地址)
    

    redirect如何跳转?

    1. 当输入 http://127.0.0.1:8000/add_press 时候, 此时的响应头如下
        HTTP/1.0 301 Moved Permanently
        Date: Sat, 02 Nov 2019 11:26:54 GMT
        Server: WSGIServer/0.2 CPython/3.6.8
        Content-Type: text/html; charset=utf-8
        Location: /add_press/
        Content-Length: 0
    
    2.  根据  Location: /add_press/, 即后端程序中redirect后面定义的地址,  向http://127.0.0.1:8000/add_press/ 发送一次请求并接收响应
    
        HTTP/1.0 200 OK
        Date: Sat, 02 Nov 2019 11:26:54 GMT
        Server: WSGIServer/0.2 CPython/3.6.8
        Content-Type: text/html; charset=utf-8
        X-Frame-Options: SAMEORIGIN
        Vary: Cookie
        Content-Length: 3356
        Set-Cookie:  csrftoken=xINH6A3h92N0jd38Jck3AhBnYp9xCZqSu7SR1AU7JP4Vmvs24Cc3hj3DYaGxhfj5; 			expires=Sat, 31-Oct-2020 11:26:54 GMT; Max-Age=31449600; Path=/
    

    返回Json格式

    JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。

    HttpResponse(json.dumps(ret))  # Content-Type: text/html; charset=utf-8
    JsonResponse(ret)      # Content-Type: application/json
    

    需求

    要求浏览器返回一个字典, 而不是一个字符串或者页面, 这种场景就需要用Json进行序列化python的字典编程json对象在浏览器显示


    版本1

    urls.py

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'test',views.Test.as_view()),
    
    ]
    

    views.py

    from django.views import View
    from django.shortcuts import HttpResponse, render, redirect
    
    
    class Test(View):
        def get(self, request):
            data={'name': 'lyysb', 'password': 123332}
            return HttpResponse(data)
    
        def post(self, request):
            pass
    

    浏览器输入http://127.0.0.1:8000/test/

    只是返回来字典的键值

    所以如果要这个字典完整在浏览器上渲染,尝试使用json格式字符串


    版本2

    修改views.py里的代码

    views.py

    from django.views import View
    from django.shortcuts import HttpResponse
    import json
    
    
    class Test(View):
        def get(self, request):
            data = {'name': 'lyy傻缺', 'password': 123332}
            return HttpResponse(json.dumps(data, ensure_ascii=False)) 
            # ensure_ascii=False参数的作用是使得中文能够在浏览器上渲染
    
        def post(self, request):
            pass
    

    浏览器输入http://127.0.0.1:8000/test/


    版本3

    使用 JsonResponse 返回json字符串

    views.py

    from django.http import JsonResponse
    
    from django.views import View
    
    
    class Test(View):
        def get(self, request):
            data = {'name': 'lyy傻缺', 'password': 123332}
            return JsonResponse(data,json_dumps_params={'ensure_ascii':False})
    
        def post(self, request):
            pass
    

    urls.py

    from django.contrib import admin
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
        url('^admin/', admin.site.urls),
        url('^test', views.MyCls.as_view())
    ]
    

    为什么 JsonResponse(ret) 的响应头的Content-Type是 application/json


    在源码中定义了 kwargs.setdefault('content_type', 'application/json')


    JsonResponse 源码


    内部调用的也是Json模块,封装了json.dumps()

    如果需要传递参数,通过 json_dumps_params 关键字传参,传参的值以字典的形式传值,因为这样 json_dumps_params的值就打散成key=value的形式为json.dumps()传递

    比如说 json.dumps(data, ensure_ascii=False),要使用JsonResponse得到同样的效果

    就这么用: JsonResponse(data,json_dumps_params={'ensure_ascii':False})

    class JsonResponse(HttpResponse):
        def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
                     json_dumps_params=None, **kwargs):
            if safe and not isinstance(data, dict):
                raise TypeError(
                    'In order to allow non-dict objects to be serialized set the '
                    'safe parameter to False.'
                )
            if json_dumps_params is None:
                json_dumps_params = {}
            kwargs.setdefault('content_type', 'application/json')
            data = json.dumps(data, cls=encoder, **json_dumps_params)
            super(JsonResponse, self).__init__(content=data, **kwargs)
    

    为什么 HttpResponse(ret) 的响应头的Content-Type是 text/html; charset=utf-8

    • 在HttpResponse源码中, Content-Type是它的父类的一个默认值形参, 默认值是None

    • 在HttpResponse源码中, 如果 Content-Type是None, 则 Content-Type 是取global_settings里的Content-Type的值

    class HttpResponseBase(six.Iterator):
        status_code = 200
        
        def __init__(self, content_type=None, status=None, reason=None, charset=None):
           if content_type is None:
                content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE,
                                                   self.charset)
            self['Content-Type'] = content_type
    
    • 在global_settings中默认Content-Type 是 text/html; charset=utf-8
    DEFAULT_CONTENT_TYPE = 'text/html'
    DEFAULT_CHARSET = 'utf-8'
    
  • 相关阅读:
    php 加反斜杠的原因与处理办法
    python2.7 正则表达式的学习
    关于thinkhphp3.1中废弃 preg_replace /e 修饰符
    python2.7 函数的参数学习
    Laravel中Homestead添加多站点时遇到问题
    安装pywin32时,出现找不到python27注册信息的解决办法
    递归例子
    在SUSE平台启动和关闭mysql服务
    SUSE11 安装mysql
    delphi调用dll动态库
  • 原文地址:https://www.cnblogs.com/cjwnb/p/11616621.html
Copyright © 2011-2022 走看看