zoukankan      html  css  js  c++  java
  • Django--视图层(views)

    视图函数

    1. 视图函数,简称视图 通过urls.py的映射 与路由相对应.
    2. 视图函数 默认定义在views.py文件中,用来处理web请求信息以及返回响应信息的函数
    3. 研究视图函数掌握两个对象即可.

    请求对象(HttpRequest)

    1. 前提:根据前两天的学习已经知道http协议请求报文中有请求行,首部信息,/r/n内容主体.
    2. Django将http协议请求报文中的内容封装到了HttpRequest对象中,Django会将httprequest对象当做参数传给视图函数的第一个参数request,通过访问这个对象的属性就可以提取http协议的请求数据.

    HttpRequest对象常用属性 1

    一.HttpRequest.method
      获取请求使用的方法(值为纯大写的字符串格式)。例如:"GET"、"POST"
       应该通过该属性的值来判断请求方法
    
    二.HttpRequest.GET
      值为一个类似于字典的QueryDict对象,封装了GET请求的所有参数,可通过HttpRequest.GET.get('键')获取相对应的值
      
    三.HttpRequest.POST
       值为一个类似于字典的QueryDict对象,封装了POST请求所包含的表单数据,可通过HttpRequest.POST.get('键')获取相对应的值
       
       针对表单中checkbox类型的input标签、select标签提交的数据,键对应的值为多个,需要用:HttpRequest.POST.getlist("hobbies")获取存有多个值的列表,同理也有HttpRequest.GET.getlist("键")
    

    案例:

    urls.py 添加映射关系

    from django.urls import re_path
    from app01 import views
    
    urlpatterns = [
        re_path(r'^login/$',views.login),
    ]
    

    views.py 处理web请求信息以及返回响应信息的函数

    from django.shortcuts import render,HttpResponse
    
    def login(request):
        if request.method == 'GET':
            # 当请求url为:http://127.0.0.1:8001/login/?a=1&b=2&c=3&c=4&c=5
            # 请求方法是GET,?后的请求参数都存放于request.GET中
            print(request.GET)
            # 输出<QueryDict: {'a': ['1'], 'b': ['2'], 'c': ['3', '4', '5']}>
    
            # 获取?后参数的方式为
            a=request.GET.get('a') # 1
            b=request.GET.get('b') # 2
            c=request.GET.getlist('c') # ['3', '4', '5']
    
            return render(request,'login.html')
        elif request.method == 'POST':
            # 在输入框内输入用户名egon、年龄18,选择爱好,点击提交
            # 请求方法为POST,表单内的数据都会存放于request.POST中
            print(request.POST) 
            # 输出<QueryDict: {..., 'name': ['egon'], 'age': ['18'], 'hobbies': ['music', 'read']}>
    
            # 获取表单中数据的方式为
            name=request.POST.get('name') # egon
            age=request.POST.get('age') # 18
            hobbies=request.POST.getlist('hobbies') # ['music', 'read']
    
            return HttpResponse('提交成功')
    

    在templates目录下新建HTML页面 login.html

    在templates目录下新建login.html
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
    </head>
    <body>
    
    <!--
    method="post"代表在提交表单时会以POST方法提交表单数据
    action="/login/" 代表表单数据的提交地址为http://127.0.0.1:8001/login/,可以简写为action="/login/",或者action=""
    -->
    <form action="http://127.0.0.1:8001/login/" method="post">
        {% csrf_token %} <!--强调:必须加上这一行,后续我们会详细介绍-->
        <p>用户名:<input type="text" name="name"></p>
        <p>年龄:<input type="text" name="age"></p>
        <p>
            爱好:
            <input type="checkbox" name="hobbies" value="music">音乐
            <input type="checkbox" name="hobbies" value="read">阅读
            <input type="checkbox" name="hobbies" value="dancing">跳舞
        </p>
        <p><input type="submit" value="提交"></p>
    
    </form>
    </body>
    </html
    

    HttpRequest 对象常用属性2

    HttpRequest.body:

       当浏览器基于http协议的POST方法提交数据时,
       数据会被放到请求体中发送给django,django会将接收到的请求体数据存放于HttpRequest.body属性中
       因为该属性的值为Bytes类型,所以通常情况下直接处理Bytes、并从中提取有用数据的操作是复杂而繁琐的,
       django会对它做进一步的处理与封装以便我们更为方便地提取数据
    

    对于form表单来说,提交数据的常用方法为GET与POST

    GET为请求数据,POST是请求的时候发送给数据

    1.表单属性 method=='GET' 提交表单的时候,表单内数据不会存放在请求体中,而是将会表单数据按照k1=v1&k2=v2&k3=v3的格式放在url中,然后发送给django,django会将这些数据封装到request.GET中,这个时候request.body是为空
    2.表单属性为'POST',request.body提交表单的时候,表单的数据都会存放在请求体,django封装request.body里面,然后django为了方便提取数据做进一步的处理.
    

    form表单对提交的表的数据有两种常用的编码格式,通过enctype进行设置,

    编码格式1(默认的编码格式) enctype='application/x-www-form-urlencoded'
    编码格式2(使用form表单上传文件时只能这个编码):enctype='multipart/form/-data'
    编码格式2数据量要大于编码格式1 如果不需要上传文件,那么就推荐同编码格式1比较精简
    
    

    案例 from表单上传文件

    urls.py

    from django.urls import path,register_converter,re_path
    from app01 import views
    
    urlpatterns = [
    	re_path(r^'register/$',views.register),
    ]
    
    

    views.py

    from django.shortcuts import render,HttpResponse
    def register(request):
        if request.method == 'GET':
    		return render(request,'register.html')
        elif request.method =='post':
            print(requets.body)
            # 从request.POST中获取用户名
            name = request.POST.get('name')
            
    

    在templates目录下新建register.html

    建立表单,需要将表单的编码格式改成multipart/form-data

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册页面</title>
    </head>
    <body>
    
    <form action="" method="POST" enctype="multipart/form-data" >
        {% csrf_token %}
        <p>
            用户名:<input type="text" name="name">
        </p>
        <p>
            头像:<input type="file" name="header_img">
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    </form>
    </body>
    </html>
    

    HttpRequest对象常用属性3

    1.HttpRequest.path
    	获取url地址的路径部分,只包含路径部分
    2.HttpRequest.get_full_path()
    	获取url地址完整path,而且也包含参数部分
    也就是如果请求的地址是http://127.0.0.1:8001/order/?name=egon&age=10#_label3,
            
    HttpRequest.path的值为"/order/"
    HttpRequest.get_full_path()的值为"/order/?name=egon&age=10"   
    

    案例:

    url.py

    from django.urls import path,register_converter,re_path
    from app01 import views
    urlpatterns = [
    	re_path(r'^order',views.order),
    ]
    

    views.py

    from django.shortcuts import render,HttpResponse
    
    # 针对请求的url地址:http://127.0.0.1:8001/order/?name=egon&age=10#_label3
    # 从域名后的最后一个“/”开始到“?”为止是路径部分,即/order/
    # 从“?”开始到“#”为止之间的部分为参数部分,即name=egon&age=10
    def order(request):
        print(request.path) # 结果为“/order/”
        print(request.get_full_path()) # 结果为"/order/?name=egon&age=10"
    
        return HttpResponse('order page')
    

    HttpRequest对象常用属性part4

    一.HttpRequest.META
       值为包含了HTTP协议的请求头数据的Python字典,字典中的key及期对应值的解释如下
        CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
        CONTENT_TYPE —— 请求的正文的MIME类型。
        HTTP_ACCEPT —— 响应可接收的Content-Type。
        HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
        HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
        HTTP_HOST —— 客服端发送数据的目标主机与端口
        HTTP_REFERER —— Referring 页面。
        HTTP_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 的键时,
        都会
        1、将所有字母大写
        2、将单词的连接符替换为下划线
        3、加上前缀HTTP_。
        所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
       
    注意:下述常用属性暂且了解即可,待我们讲到专门的知识点时再专门详细讲解
    二.HttpRequest.COOKIES
      一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
    
    三.HttpRequest.session
      一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
    
    11.HttpRequest.user(用户认证组件下使用)
    
      一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
    
    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') 装饰你的视图以让响应能够正确地缓存。
    

    响应对象

    响应可以使任何形式的内容,HTML文件内容,重定向,错误,xml文档,一张图片.不论视图包含什么逻辑都要返回响应

    响应三剑客

    from django.shortcuts import HttpResponse,render,redirect
    

    HttpResponse()

    括号内直接跟一个具体的字符串作为响应体,比较直接简单

    render()

    render(request,template_name[context])
    1.request 用户生成响应的请求对象,固定必须传入的第一个参数
    2. template_name:要是用的模板完整的名称,必须传,render就会去templates文件夹下找模板文件,
    3 context  可以选的参数, 可以传一个字典用来替换模板文件中的变量 
    

    redirect()

    返回重定向地址,也可以是一个完整的url

    return redirect('/xxx/')

    return redirect('http"//www.baidu.com/')

    重定向状态码301与302区别

    301代表旧地址资源被永久移除.搜索引擎在抓取新内容的时候也将就得网址转换成重定向之后的地址

    302表示旧地址资源还在(与上面相反)临时从旧到新地址

    总结:从SEO层面考虑,302好于301

    JsonResponse

    先看一下代码

    向前端返回一个json格式字符串的两种方式

    JsonResponse默认只支持序列化字典 如果你想序列化其他类型(json能够支持的类型) 你需要将safe参数由默认的True改成False

    方式一

    import json
    def my_view(request):
        data = ['egon','kevin']
        return HttpResonse(json.dumps(data))
    
    

    方式二

    from django.http import JsonResponse
    def my_view(request):
        data = ['egon',kevin]
        return JsonResponse(data,safe=False)
    

    JsonResponse
        返回json格式数据的
        
        为什么要给前端返回json格式字符串
        
        前后端分离  就是基于json格式传输数据
        后端就专门写接口 前端调用你这个接口 就能够拿到一个
        json格式的字符串
        然后前端利用序列化反序列转换成前端对应的数据类型
        
        js常用数据类型
            数值类型
            字符类型
            数组  []
            自定义对象 {}
            undefined与null
            布尔值 true false
            symbol
    

            前端							后端
            JSON.stringify 序列化   >>>   json.dumps
            JSON.parse     反序列   >>>   json.loads
    

            复习
                python后端
                    json.dumps
                    json.loads
    

    FBV和CBV

    django的视图层是由两种形式构成:FBV和CBV

    1. FBV基于函数的视图(Function Base View)
    2. CBV基于类的视图(Class Base View)

    form表单上传文件
    注意事项
    1.提交方式必须是post
    2.enctype参数必须有默认的urlencoded变成formdata

    views.py

    from django.shortcuts import render
    def up(request):
        if request.method == 'POST':
            print(request.POST)
    
    

    FBV与CBV 即CBV源码分析
    FBV(Function Based View) 基于函数的视图

    问题:

    CBV(Class Based View) 基于类的视图
        你在类中写了两个方法 一个叫get一个叫post
        为什么前端get请求来就会触发get方法
        post请求来就会触发post方法  如何实现的???
    

    1.CBC和FBV在路由匹配上规则都是一致的, 都是路由后面跟函数的内存地址,

    2.as_view()点击进去会发现它里面有一个闭包函数,返回的就是view函数,view函数里面做的是给自己写的类产生的对象去赋值,

    3.view函数又返回了dispatch方法,里面做了一个筛选get和post小写的字符串,如果不在默认的8个请求方式,那么就返回一个报错的函数,

    4在的话就将通过getattr反射函数的地址最后再调用获取的方法

        # CBV路由
        url(r'^reg/',views.MyReg.as_view())
        
        @classonlymethod
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)  # cls就是我们自己的写的MyReg类
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                # 上面的一通操作 就是给我们自己写的类的对象赋值
                return self.dispatch(request, *args, **kwargs)
                # 对象在查找属性或方法的时候 顺序是什么?  先从自己找 再从产生对象的类中找  再去类的父类中找...
                """也就意味着你在看源码的时候 你一定要牢记上面的话"""
            return view
        
        # views.py 
        from django.views import View
        class MyReg(View):
            def get(self,request):
                return render(request,'reg.html')
    
            def post(self,request):
                return HttpResponse("我是MyReg类中post方法")
    

    **"""CBV最精髓的部分""" **

            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)
    
    handler = getattr(自己写的类产生的对象,'小写的请求方法(getpost)','获取不到对应的方法就报错')
    
    handler就是我们自己定义的跟请求方法相对应的方法的函数内存地址
    
    ​            else:
    ​                handler = self.http_method_not_allowed
    ​            return handler(request, *args, **kwargs)  # 在调用获取到的方法
    ​    
    

    案例:

    urls.py

    from django.urls import path,register_converter,re_path
    from app01 import views
    
    urlpatterns = [
        re_path(r'^login/',views.LoginView.as_view()), # 必须调用类下的方法as_view
    ]
    

    views.py

    from django.shortcuts import render,HttpResponse,redirect
    from django.views import View
    
    class LoginView(View):
        def dispatch(self, request, *args, **kwargs): # 可在该方法内做一些预处理操作
            # 当请求url为:http://127.0.0.1:8008/login/会先触发dispatch的执行
            # 如果http协议的请求方法为GET,则调用下述get方法
            # 如果http协议的请求方法为POST,则调用下述post方法
            obj=super().dispatch(request, *args, **kwargs) # 必须继承父类的dispatch功能
            return obj # 必须返回obj
    
        def get(self,request):
            return render(request,'login.html')
    
        def post(self,request):
            name=request.POST.get('name')
            pwd=request.POST.get('pwd')
            if name  == 'egon' and pwd == '123':
                res='登录成功'
            else:
                res='用户名或密码错误'
            return HttpResponse(res)
    

    测试:

    python manage.py runserver 8001 
    # 验证GET请求:在浏览器输入:http://127.0.0.1:8001/login/
    # 验证POST请求:在表单内输入数据然后提交
    

    采用CBV可以引入面向对象的思想对数据进行更高程度的封装

  • 相关阅读:
    BZOJ4416 SHOI2013阶乘字符串(状压dp)
    雅礼集训 Day2 T3 联盟 解题报告
    雅礼集训 Day1 T2 折射
    雅礼集训 Day1 T1 养花
    P1494 [国家集训队]小Z的袜子/莫队学习笔记(误
    洛谷 P2155 [SDOI2008]沙拉公主的困惑 解题报告
    动态MST
    洛谷 P2606 [ZJOI2010]排列计数 解题报告
    牛客 2018NOIP 模你赛2 T2 分糖果 解题报告
    洛谷 P3396 哈希冲突 解题报告
  • 原文地址:https://www.cnblogs.com/jhpy/p/11729658.html
Copyright © 2011-2022 走看看