zoukankan      html  css  js  c++  java
  • 第四章 Django框架——视图层views

    第四章 Django框架——视图层views

    一、视图函数

    二、HttpRequest请求对象

    三、HTTPResponse响应对象

    四、CBV和FBV

    五、JsonResponse

    六、简单的文件上传方法

    一、视图函数

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

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

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

    from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
    import datetime
    
    def current_datetime(request):
        now = datetime.datetime.now()
        html = "<html><body>It is now %s.</body></html>" % now
        return HttpResponse(html)

    让我们逐行阅读上面的代码:

    • 首先,我们从 django.shortcuts模块导入了HttpResponse类,以及Python的datetime库。

    • 接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request

      注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。

    • 这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

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

    二、HttpRequest请求对象

     HttpRequest请求对象下的属性(除了特殊说明的之外,其他均为只读的):

     form表单不写method的情况下,默认为GET请求,切记改为POST请求

     何时使用POST请求与GET请求:
     ①POST:向服务器提交数据

     ②GET:请求数据,请求页面

    请求相关的常用值:

    • path_info     返回用户访问url,不包括域名
    • method        请求中使用的HTTP方法的字符串表示,全大写表示。
    • GET              包含所有HTTP  GET参数的类字典对象
    • POST           包含所有HTTP POST参数的类字典对象
    • body            请求体,byte类型 request.POST的数据就是从body里面提取到的

     

    HttpRequest请求对象下的常用方法:

    1.HttpRequest.get_host()
    
      根据从HTTP_X_FORWARDED_HOST(如果打开 USE_X_FORWARDED_HOST,默认为False)和 HTTP_HOST 头部信息返回请求的原始主机。
       如果这两个头部没有提供相应的值,则使用SERVER_NAME 和SERVER_PORT,在PEP 3333 中有详细描述。
    
      USE_X_FORWARDED_HOST:一个布尔值,用于指定是否优先使用 X-Forwarded-Host 首部,仅在代理设置了该首部的情况下,才可以被使用。
    
      例如:"127.0.0.1:8000"
    
      注意:当主机位于多个代理后面时,get_host() 方法将会失败。除非使用中间件重写代理的首部。
    
     
    
    2.HttpRequest.get_full_path()
    
      返回 path,如果可以将加上查询字符串。
    
      例如:"/music/bands/the_beatles/?print=true"
    
     
    
    3.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    
      返回签名过的Cookie 对应的值,如果签名不再合法则返回django.core.signing.BadSignature。
    
      如果提供 default 参数,将不会引发异常并返回 default 的值。
    
      可选参数salt 可以用来对安全密钥强力攻击提供额外的保护。max_age 参数用于检查Cookie 对应的时间戳以确保Cookie 的时间不会超过max_age 秒。
    
            复制代码
            >>> request.get_signed_cookie('name')
            'Tony'
            >>> request.get_signed_cookie('name', salt='name-salt')
            'Tony' # 假设在设置cookie的时候使用的是相同的salt
            >>> request.get_signed_cookie('non-existing-cookie')
            ...
            KeyError: 'non-existing-cookie'    # 没有相应的键时触发异常
            >>> request.get_signed_cookie('non-existing-cookie', False)
            False
            >>> request.get_signed_cookie('cookie-that-was-tampered-with')
            ...
            BadSignature: ...    
            >>> request.get_signed_cookie('name', max_age=60)
            ...
            SignatureExpired: Signature age 1677.3839159 > 60 seconds
            >>> request.get_signed_cookie('name', False, max_age=60)
            False
            复制代码
             
    
    
    4.HttpRequest.is_secure()
    
      如果请求时是安全的,则返回True;即请求通是过 HTTPS 发起的。
    
     
    
    5.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') 装饰你的视图以让响应能够正确地缓存。
    
    请求相关方法
    方法

    注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:

    request.POST.getlist("hobby")

    三、HTTPResponse响应对象

     1.HTTPResponse()

     HttpResponse()括号内直接跟一个具体的字符串作为响应体。

     属性:

    • HttpResponse.content:响应内容
    • HttpResponse.charset:响应内容的编码
    • HttpResponse.status_code:响应的状态码

     2.render()

     结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象,简而言之就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。

      语法:render(request, template_name[, context])

      参数:

    • request: 用于生成响应的请求对象。
    • template_name:要使用的模板的完整名称,可选的参数
    • context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
    • local():可以直接将函数中所有的变量全部传给模板。当然这可能会传递一些多余的参数,有点浪费内存的嫌疑

     3.redirect()

     传递要重定向的一个硬编码的URL,也可以是一个完整的URL。

       语法:

    def my_view(request):
        ...
        return redirect('/some/url/')
    def my_view(request):
        ...
        return redirect('http://www.baidu.com/') 

    四、CBV和FBV

     FBV(function base view):基于函数的view,就叫FBV

    def add_class(request):
        if request.method == "POST":
            class_name = request.POST.get("class_name")
            models.Classes.objects.create(name=class_name)
            return redirect("/class_list/")
        return render(request, "add_class.html")

     CBV(class base view):基于类的view,就叫CBV

    Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:

    1. 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
    2. 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性

    使用步骤:

     ①使用前切记导入View,将创建的类继承自View

     from django.views import View

     ②该类会自动根据post请求与get请求自动分辨请求类型,选择对应的函数def get()或者def post()

     ③dispatch类似装饰器,可以在def get()或者def post()前后添加代码

         记得继承类obj=super().dispatch(request, *args, **kwargs),在其前后添加代码

     ④在路由调用视图函数时记得调用as_view()方法

    from django.views import View
    class AddPublish(View):
        def dispatch(self, request, *args, **kwargs):
            print(request)
            print(args)
            print(kwargs)
            # 可以写类似装饰器的东西,在前后加代码
            obj=super().dispatch(request, *args, **kwargs)
            return obj
    
        def get(self,request):
            return render(request,'index.html')
        def post(self,request):
            request
            return HttpResponse('post')

    使用装饰器装饰CBV(dispatch)

    类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。

    Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。

    # 使用CBV时要注意,请求过来后会先执行dispatch()这个方法,如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,
    这个dispatch方法就和在FBV上加装饰器的效果一样。
    class Login(View): def dispatch(self, request, *args, **kwargs): print('before') obj = super(Login,self).dispatch(request, *args, **kwargs) print('after') return obj def get(self,request): return render(request,'login.html') def post(self,request): print(request.POST.get('user')) return HttpResponse('Login.post')

    五、JsonResponse

    切记:JsonResponse封装的方法只能是字典形式,否则会报错

    如果一定要序列化列表,在JsonResponse内添加safe=false

    原始手动自己打包json

    def json_test(request):
        data = {'name':'xiaohei','age':18}
        import json
        return HttpResponse(json.dumps(data))

    django方法JsonResponse

    def json_test(request):
        data = {'name':'xiaohei','age':18}
        # import json
        # data_str = json.dumps(data)
        from django.http import JsonResponse
        return JsonResponse(data)

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

    from django.http import JsonResponse
    
    response = JsonResponse({'foo': 'bar'})
    print(response.content)
    
    b'{"foo": "bar"}'

    默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。

    response = JsonResponse([1, 2, 3], safe=False)

    六、简单的文件上传方法

    html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>上传文件</title>
    </head>
    <body>
    <form action="/upload/" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username">
        密码:<input type="password" name="userpassword">
        上传头像:<input type="file" name="photo">
        <input type="submit" value="开始上传">
    </form>
    </body>
    </html>

    urls

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^upload/',views.Upload.as_view())
    ]

    python

    from django.shortcuts import *
    from django.views import View
    
    # Create your views here.
    
    class Upload(View):
        def get(self,request):
            return render(request,'test.html')
        def post(self,request):
            # print(request.FILES)
            # 从请求的FILES中获取上传文件的文件名,file为页面上type=files类型input的name属性值
            filename = request.FILES["photo"].name
            # 在项目目录下新建一个文件
            with open(filename, "wb") as f:
                # 从上传的文件对象中一点一点读
                for chunk in request.FILES["photo"].chunks():
                    # 写入本地文件
                    f.write(chunk)
            return HttpResponse("上传OK")
  • 相关阅读:
    Redundant Paths 分离的路径(边双连通分量)
    bzoj2208 [Jsoi2010] 连通数(tarjan点双连通分量 // dfs)
    [bzoj3331] [BeiJing2013] 压力(tarjan 点双连通分量)
    [ BZOJ1123 ] BLO(tarjan点双连通分量)
    bitset小总结
    牛客328B Rabbit的工作(1)
    # Codeforces Round #529(Div.3)个人题解
    HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)
    istringstream()函数的用法
    codeforces 1077F1
  • 原文地址:https://www.cnblogs.com/neymargoal/p/9594203.html
Copyright © 2011-2022 走看看