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

    视图层

    Django视图层,视图就是Django项目下的views.py文件,它的内部是一系列的函数或者是类,用来专门处理客户端访问请求后处理请求并且返回相应的数据,相当于一个中央情报处理系统

    视图层,熟练掌握两个对象即可:请求对象(request)和响应对象(HttpResponse)

    HttpRequest对象

    request属性

    django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。 除了特殊说明的之外,其他均为只读的

    1.HttpRequest.GET
    
      一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
    
    2.HttpRequest.POST
    
      一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
    
      POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中
      	  没有任何的数据,QueryDict 对象依然会被创建。
       因此,不应该使用 if request.POST  来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
      另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
       
       注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
            request.POST.getlist("hobby")
    
    3.HttpRequest.body
    
      一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,
      例如:二进制图片、XML,Json等。
      但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
    
    
    4.HttpRequest.path
    
      一个字符串,表示请求的路径组件(不含域名)。
      例如:"/music/bands/the_beatles/"
    
    5.HttpRequest.method
    
      一个字符串,表示请求使用的HTTP 方法。必须使用大写。
      例如:"GET"、"POST"
    
    
    6.HttpRequest.encoding
    
      一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
       这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
       接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
       如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
    
    
    7.HttpRequest.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 —— 服务器的端口(是一个字符串)。
       从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
        都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_  前缀。
        所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
    
    8.HttpRequest.FILES
    
      一个类似于字典的对象,包含所有的上传文件信息。
       FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
      注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
       包含数据。否则,FILES 将为一个空的类似于字典的对象。
    
    
    9.HttpRequest.COOKIES
    
      一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
    
    
    10.HttpRequest.session
    
       一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
        完整的细节参见会话的文档。
    
    
    11.HttpRequest.user(用户认证组件下使用)
    
      一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
    
      如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。
      你可以通过 is_authenticated() 区分它们。
    
        例如:
    
        if request.user.is_authenticated():
            # Do something for logged-in users.
        else:
            # Do something for anonymous users.
    
    
           user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
    
         -------------------------------------------------------------------------------------
    
        匿名用户
        class models.AnonymousUser
    
        django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,
        但具有下面几个不同点:
    
        id 永远为None。
        username 永远为空字符串。
        get_username() 永远返回空字符串。
        is_staff 和 is_superuser 永远为False。
        is_active 永远为 False。
        groups 和 user_permissions 永远为空。
        is_anonymous() 返回True 而不是False。
        is_authenticated() 返回False 而不是True。
        set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
        New in Django 1.8:
        新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
    

    request常用方法

    1.HttpRequest.get_full_path()
    
      返回 path,如果可以将加上查询字符串。
    
      例如:"/music/bands/the_beatles/?print=true"
      注意和path的区别:http://127.0.0.1:8001/order/?name=lqz&age=10
    
    2.HttpRequest.is_ajax()
    
      如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 
      相应的首部是否是字符串'XMLHttpRequest'。
    
      大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 
      调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
    
      如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 
      的 cache middleware,你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图
      以让响应能够正确地缓存。
    
    

    小白必会三板斧(HttpResponse对象)

    • HttpResponse()

      • 返回字符串类型的数据

    HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接很简单,所以这里主要介绍后面两种形式

    • render ()

      • 返回html页面,还可以使用模板语法
    render(request, template_name[, context])结合一个给定的模板和一个给定的上下文字典,
           							  并返回一个渲染后的 HttpResponse 对象。
    参数:
         request: 用于生成响应的请求对象。
    
         template_name:要使用的模板的完整名称,可选的参数
    
         context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,
               视图将在渲染模板之前调用它。
    
    render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
    
    • redirect ()

      • 传递要重定向的一个硬编码的URL
    def my_view(request):
        ...
        return redirect('/some/url/')
    

    也可以是一个完整的URL:

    def my_view(request):
        ...
        return redirect('http://www.baidu.com/')
    1)301和302的区别。
    
      301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到
      一个新的URL地址,这个地址可以从响应的Location首部中获取
      (用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。
    
      他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),
      搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;
    
      302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,
      搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301
    
     
    
    2)重定向原因:
    (1)网站调整(如改变网页目录结构);
    (2)网页被移到一个新地址;
    (3)网页扩展名改变(如应用需要把.php改成.Html或.shtml)。
          这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让
          访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的
        网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。
    

    三板斧本质

    django视图函数必须要返回一个HttpResponse对象? 正确!

    django视图函数必须有一个返回值,并且返回值的数据类型必须是HttpResponse对象

    # 研究三者源码可以得出结论
    # HttpResponse
    class HttpResponse(HttpResponseBase):
        """
        An HTTP response class with a string as content.
        # 以字符串作为内容的HTTP响应类
        This content that can be read, appended to or replaced.
        # 可以读取、添加或替换的内容
        """
        streaming = False
    
        def __init__(self, content=b'', *args, **kwargs):
            super(HttpResponse, self).__init__(*args, **kwargs)
            # 内容是一个字节串。参见' content '属性方法
            # Content is a bytestring. See the `content` property methods.
            self.content = content 
            
    # render        
    def render(request, template_name, context=None, content_type=None, status=None, using=None):
            """
            Returns a HttpResponse whose content is filled with the result of calling
            django.template.loader.render_to_string() with the passed arguments.
            # 返回一个HttpResponse,它的内容中填充了调用的结果
    		# django.template.loader.render_to_string()和传递的参数
            """
            content = loader.render_to_string(template_name, context, request, using=using)
            return HttpResponse(content, content_type, status)
      
    # redirect内部是继承了HttpRespone类
    

    JsonResponse

    给前端返回json格式的字符串

    方式1:自己序列化

    import json
    def func(request):
        d = {'user':'jason好帅','password':123}    
        res = json.dumps(d,ensure_ascii=False)
        return HttpResponse(res)
    

    方式2: JsonResponse

    from django.http import JsonResponse
    def func(request):
        d = {'user':'jason好帅','password':123}
        return JsonResponse(d)
     #  return JsonResponse(d,json_dumps_params={'ensure_ascii':False} )
        
    ps:额外参数补充
        json_dumps_params={'ensure_ascii':False}  # 看源码
        safe=False  # 看报错信息
     
    # JsonResponse返回的也是HttpResponse对象
    

    上传文件

    前端form表单上传文件注意事项
    	 1.method必须是post
         2.enctype参数需要修改为multipart/form-data
    
    后端暂时需要注意的是
          1.配置文件中注释掉csrfmiddleware中间件
          2.通过request.FILES获取用户上传的post文件数据       
    
    def func3(request):
        if request.method == 'POST':
            print(request.POST)
            file_obj = request.FILES.get('myfile')
            print(file_obj.name)  # 获取文件名称
            with open(r'%s'%file_obj.name,'wb') as f:
                for chunks in file_obj.chunks():
                    f.write(chunks)
        return render(request,'func3.html')
    

    FBV与CBV

    FBV基于函数的视图(Function base view)我们前面写的视图函数都是FBV
    CBV基于类的视图(Class base view)

    视图文件中除了用一系列的函数来对应处理客户端请求的数据逻辑外,还可以通过定义类来处理相应的逻辑

    CBV基本使用

    # views.py
    from django.shortcuts import render,HttpResponse,redirect
    from django.views import View
    class MyView(View):
        def get(self,request):
            return HttpResponse("get方法")
        def post(self,request):
            return HttpResponse("post方法")
        
    # urls.py    
    url(r'^func4',views.MyView.as_view())
    """为什么能够自动根据请求方法的不同执行不同的方法"""
    

    1. CBV与FBV路由匹配本质

    # urls.py  
    urlpatterns = [
    	url(r'^func4',views.MyView.as_view()) # CBV写法
        # 等价  CBV路由配置本质跟FBV一样
        url(r'^func4',views.view) # FBV写法
    ] 
    

    2. 突破口:

    知识点:函数名/方法名:加括号执行优先级最高
    CBV写的是as_view(),加括号意味着在项目启动就会执行,那么我们大胆猜测
    	 要么是被@staicmethod修饰的静态方法,就是个普通函数没有形参
     	 要么是被@classmethod修饰的类方法,类来调自动将类当做第一个参数传入
    

    3. 研究一下源码

    @classonlymethod  # 类方法,就把它看成@classmethod
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs): # view是as_view的闭包
            self = cls(**initkwargs)  # self = MyView()生成一个我们自己写的类的对象
            """
            实例化出一个View类的对象,返回一个dispatch()函数,看着跟我们之前写的
            视图函数几乎一毛一样,那么我们找一下函数的上级函数没有这个方法,最后在类
            里发现了这个dispatch()函数
            """
            return self.dispatch(request, *args, **kwargs)
        return view # 返回一个函数的内存地址
    
    def dispatch(self, request, *args, **kwargs):
            # 获取当前请求并判断是否属于正常的请求(8个)
            if request.method.lower() in self.http_method_names:
                # get请求  getattr(对象,'get')   handler = 我们自己写的get方法
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            return handler(request, *args, **kwargs)  # 执行我们写的get方法并返回该方法的返回值
    # 结论:as_view()最终干的事情就是根据request请求方式来执行视图类的不同请求方法
    

    总结:以后会经常需要看源码,但是在看Python源码的时候,一定要时刻提醒自己面向对象属性方法查找顺序,先从对象自己找,再去产生对象的类里面去找,之后再去父类找,看源码只要看到了self点一个东西,一定要问自己当前这个self到底是谁。

    从来就没有正确的选择,我们只不过是要努力奋斗,使当初的选择变得正确。
  • 相关阅读:
    Clam and fish
    费马小定理求逆元模板题
    1
    DP 习题
    106. 从中序与后序遍历序列构造二叉树
    计算几何(判断四边形形状)
    中国剩余定理
    BFS模板
    DFS模板
    线段树
  • 原文地址:https://www.cnblogs.com/gfeng/p/14551596.html
Copyright © 2011-2022 走看看