zoukankan      html  css  js  c++  java
  • Python 之 Django框架( Cookie和Session、Django中间件、AJAX、Django序列化)

    12.4 Cookie和Session

    12.41 cookie

    Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息

    获取Cookie:

    request.COOKIES['login']                           #找不到时报错
    login_flag = request.COOKIES.get("login","")        #找不到时返回None
    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    login_flag = request.get_signed_cookie("login",default="",salt="shanghais1hao")#找不到时返回默认值空

    设置Cookie:给HttpResponse、render、redirect实例化的对象设置cookie

    rep = HttpResponse("xxxx")
    rep = render(request, "book_list.html")
    rep = redirect('/book_list/')
    ​
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
    rep.set_signed_cookie("login", "ok", salt="shanghais1hao", max_age=None)

    删除Cookie:给HttpResponse、render、redirect实例化的对象删除cookie

    def logout(request):
        rep = redirect("/login/")
        rep.delete_cookie("login")      # 删除用户浏览器上之前设置的cookie值
        return rep

    12.42 Session

    Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本

    获取Session

    request.session['k1']
    request.session.get('k1',None)
    login_flag = request.session.get("login")

    设置Session

    request.session['k1'] = 123
    request.session.setdefault('k1',123) # 存在则不设置,不存在则设置
    request.session["login"] = "OK"
    request.session["user"] = username

    删除Session

    def logout(request):
        request.session.flush() 
        #删除当前的会话session数据并删除会话的Cookie,这用于确保前面的会话数据不可以再次被用户的浏览器访问
        request.session.delete()        # 删除当前会话的所有Session数据
        return redirect("/login/")
    ​
    del request.session['login']

    所有 键、值、键值对:

    request.session.keys()      #dict_keys(['login', 'user', '_session_expiry'])
    request.session.values()    #dict_values(['OK', 'alex', 1209600])
    request.session.items()     #dict_items([('login', 'OK'), ('user', 'alex'), ('_session_expiry', 1209600)])
    request.session.iterkeys()
    request.session.itervalues()
    request.session.iteritems()

    其他session的属性和方法:

    # 会话session的key
    request.session.session_key                 #k69mo6fu6qmvq7hpapdy54erpce1ksy5
    # 将所有Session当前日期大于失效日期的数据删除
    request.session.clear_expired()
    # 检查会话session的key在数据库中是否存在
    request.session.exists("session_key")
    # 设置会话Session和Cookie的超时时间
    request.session.set_expiry(value)
        * 如果value是个整数,session会在数秒数后失效。
        * 如果value是个datatime或timedelta,session就会在这个时间后失效。
        * 如果value是0,用户关闭浏览器session就会失效。
        * 如果value是None,session会依赖全局session失效策略。
    request.session.set_expiry(60 * 60 * 24 * 14)
    12.421 Django中的Session配置(settings.py)
    1. 数据库Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
    2. 缓存Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
    3. 文件Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 
    4. 缓存+数据库
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
    5. 加密Cookie Session
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
    ​
    其他公用设置项:
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

    12.5 Django中间件

    中间件:在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

    process_request(self,request)
    process_view(self, request, view_func, view_args, view_kwargs)
    process_template_response(self,request,response)
    process_exception(self, request, exception)
    process_response(self, request, response)

    以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户

    自定义一个中间件示例:

    from django.utils.deprecation import MiddlewareMixin
    ​
    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("MD1里面的 process_request")
        def process_response(self, request, response):
            print("MD1里面的 process_response")
            return response

    12.51 中间件版登录验证

    中间件版的登录验证需要依靠session,所以数据库中要有django_session表

    middlewares.py:

    class AuthMD(MiddlewareMixin):
        white_list = ['/login/', ]  # 白名单
        balck_list = ['/black/', ]  # 黑名单
    def process_request(self, request):
            from django.shortcuts import redirect, HttpResponse
    ​
            next_url = request.path_info
            #print(request.path_info, request.get_full_path())
            if next_url in self.white_list or request.session.get("user"):
                return
            elif next_url in self.balck_list:
                return HttpResponse('This is an illegal URL')
            else:
                return redirect("/login/?next={}".format(next_url))

    在settings.py中注册:

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'middlewares.AuthMD',
    ]

    urls.py:

    from django.conf.urls import url
    from app01 import views
    ​
    urlpatterns = [
        url(r'^index/$', views.index),
        url(r'^login/$', views.login, name='login'),
    ]

    views.py:

    from django.shortcuts import render, HttpResponse, redirect
    def index(request):
        return HttpResponse('this is index')
    ​
    def home(request):
        return HttpResponse('this is home')
    ​
    def login(request):
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    ​
            if user == "Q1mi" and pwd == "123456":           
                request.session["user"] = user# 设置session           
                next_url = request.GET.get("next") # 获取跳到登陆页面之前的URL         
                if next_url:
                    return redirect(next_url)# 如果有,就跳转回登陆之前的URL         
                else:
                    return redirect("/index/") # 否则默认跳转到index页面
        return render(request, "login.html")

    login.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>登录页面</title>
    </head>
    <body>
    <form action="{% url 'login' %}">
        <p>
            <label for="user">用户名:</label>
            <input type="text" name="user" id="user">
        </p>
        <p>
            <label for="pwd">密 码:</label>
            <input type="text" name="pwd" id="pwd">
        </p>
        <input type="submit" value="登录">
    </form>
    </body>
    </html>

    12.6 AJAX

    AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

    AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

    AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

    • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;

    • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

    AJAX优点:

    • AJAX使用JavaScript技术向服务器发送异步请求;

    • AJAX请求无须刷新整个页面;

    • 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;

    页面输入两个整数,通过AJAX传输到后端计算出结果并返回:

    urls.py:

    urlpatterns = [
        ...
        url(r'^ajax_add/', views.ajax_add),
        url(r'^ajax_demo1/', views.ajax_demo1),
        ...   
    ]

    views.py:

    def ajax_demo1(request):
        return render(request, "ajax_demo1.html")
    ​
    def ajax_add(request):
        i1 = int(request.GET.get("i1"))
        i2 = int(request.GET.get("i2"))
        ret = i1 + i2
        return JsonResponse(ret, safe=False)

    ajax_demo1.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="x-ua-compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>AJAX局部刷新实例</title>
    </head>
    <body>
    <input type="text" id="i1">+
    <input type="text" id="i2">=
    <input type="text" id="i3">
    <input type="button" value="AJAX提交" id="b1">
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
      $("#b1").on("click", function () {
        $.ajax({
          url:"/ajax_add/",                           #往哪里发送请求
          type:"GET",                                 #请求的方法
          data:{"i1":$("#i1").val(),"i2":$("#i2").val()},#发送到后端的请求数据
          success:function (data) {                    #请求被正常响应时自动执行的回调函数
            $("#i3").val(data);
          }
        })
      })
    </script>
    </body>
    </html>

    12.61AJAX请求设置csrf_token

    方式一:通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="x-ua-compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>AJAX局部刷新实例</title>
    </head>
    <body>
    {% csrf_token %}
    <input type="text" id="i1">+
    <input type="text" id="i2">=
    <input type="text" id="i3">
    <input type="button" value="AJAX提交" id="b1">
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
      $("#b1").on("click", function () {
        $.ajax({
          url: "/cookie_ajax/",
          type: "POST",
          data: {"i1":$("#i1").val(),"i2":$("#i2").val(),"csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中
          },
          success: function (data) {
            console.log(data);
          }
        })
      })      
    </script>
    </body>
    </html>

    方式二:通过获取返回的cookie中的字符串,放置在请求头中发送。注意:需要引入一个jquery.cookie.js插件。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="x-ua-compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>AJAX局部刷新实例</title>
    </head>
    <body>
    <input type="text" id="i1">+
    <input type="text" id="i2">=
    <input type="text" id="i3">
    <input type="button" value="AJAX提交" id="b1">
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
    $("#b1").on("click", function () {
        $.ajax({
          url: "/cookie_ajax/",
          type: "POST",
          headers: {"X-CSRFToken": $.cookie('csrftoken')},  # 从Cookie取csrftoken,并设置到请求头中
          data: {"i1":$("#i1").val(),"i2":$("#i2").val()},
          success: function (data) {
            console.log(data);
          }
        })
    })
    </script>
    </body>
    </html>

    或者自己写一个getCookie方法:

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                # Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');

    12.62 Django序列化

    from app01 import models
    def persons(request):
        ret = models.Person.objects.all()
        #re=models.Person.objects.all().values_list('data')
        # import json
        # person_list = []
        # for i in ret:
        # person_list.append({"name": i.name, "age": i.age})
        # s = json.dumps(person_list)
        from django.core import serializers
        s = serializers.serialize("json", ret) #序列化对象,取出对象所有属性组成字典并序列化成json字符串
        #s = serializers.serialize("json", ret) 序列化日期类型
        return HttpResponse(s)

    12.63 AJAX上传文件

    formData的基本用法:FormData对象,可以把所有表单元素的name与value组成一个queryString,提交到后台。只需要把 form 表单作为参数传入 FormData 构造函数即可

    利用 FormData 来上传文件:

    #上传文件示例
    <body>
    <div>
        <input accept="image/*" type="file" name="avatar" id="f1">
        <input type="button" value="提交" id="b1">
    </div>
    <script src="/static/jquery-3.3.1.min.js"></script>
    <script>
    $("#b1").click(function () {
      var formData = new FormData();            #生成一个FormData对象
      formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
      formData.append("f1", $("#f1")[0].files[0]);#得到用户选中的文件对象,并向formData对象中添加键值对数据
      $.ajax({
        url: "/upload/",
        type: "POST",
        processData: false,                     #告诉jQuery不要去处理发送的数据
        contentType: false,                     #告诉jQuery不要去设置Content-Type请求头
        data: formData,
        success:function (data) {                #请求被正常响应时自动执行的回调函数
          console.log(data)
        }
      })
    })
    </script>
    </body>

    或者:

    var form = document.getElementById("form1");
    var fd = new FormData(form);

    这样也可以直接通过ajax 的 send() 方法将 fd 发送到后台。

    注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。

    views.py:

    from django.shortcuts import render, HttpResponse
    from django.http import JsonResponse
    ​
    def upload(request):
        if request.method == "POST":
            file_obj = request.FILES.get("avatar") # 获取文件对象
            with open(file_obj.name, "wb") as f:   # file_obj.name  --> 上传文件的文件名          
                for chunk in file_obj.chunks():    # 从该文件对象里一点一点读取数据,写入刚新建的文件句柄f
                    f.write(chunk)
            # return JsonResponse("OK",safe=False)
            return HttpResponse("OK")
        return render(request, "upload.html")
  • 相关阅读:
    thread ---- join
    函数传参传的是啥的思考【java Python】
    关于 私有变量的访问问题【 java python]
    编程语言的某些 概念
    python 小整数池 和intern 【整理】
    [题解] uva 11354 Bond(kruskal最小生成树+倍增LCA)
    [题解] bzoj 1016 jsoi 2008 最小生成树计数 (kruskal最小生成树)
    [题解] bzoj 1821 jsoi 2010 Group 部落划分(kruskal最小生成树)
    [题解] uva 10369 Arctic Network(kruskal最小生成树)
    [题解] 洛谷 P1550 USACO 2008 OCT 打井Watering Hole (kruskal最小生成树)
  • 原文地址:https://www.cnblogs.com/mylu/p/13679402.html
Copyright © 2011-2022 走看看