Django进阶篇

1.1 Cookie

  1、cookie简介

    1. cookie实质就是客户端硬盘中存放的键值对,利用这个特性可以用来做用户验证

    2. 比如:{“username”: “dachengzi”} #再次访问url就会携带这些信息过来

  2、前端操作cookie
      说明: 使用下面方法操cookie必须先引入jquery.cookie.js

    1. 前端获取cookie值:  var v = $.cookie(‘per_page_count‘);

    2. 前端设置cookie值:  $.cookie(‘per_page_count‘,v);

  3、后端操作cookie

    说明: response = HttpResponse(...)  或  response = render(request, ...)

    1. 后端设置cookie值:  response.set_cookie(‘username‘,"zhangsan")

    2. 后端后去cookie值:  request.COOKIES.get(‘username‘)

  4、设置cookie时常用参数 

def cookie(request):
    #1 获取cookie中username111得值
    request.COOKIES.get(‘username111‘)

    #2 设置cookie的值,关闭浏览器失效
    response.set_cookie(‘key‘,"value")
    # 设置cookie, N秒只后失效
    response.set_cookie(‘username111‘,"value",max_age=10)

    #3 设置cookie, 截止时间失效(expires后面指定那个时间点失效)
    import datetime
    current_date = datetime.datetime.utcnow()
    exp_date = current_date + datetime.timedelta(seconds=5)         #seconds指定再过多少秒过期
    response.set_cookie(‘username111‘,"value",expires=exp_date)

    #4 设置cookie是可以使用关键字salt对cookie加密(加密解密的salt中值必须相同)
    obj = HttpResponse(‘s‘)

    obj.set_signed_cookie(‘username‘,"kangbazi",salt="asdfasdf")
    request.get_signed_cookie(‘username‘,salt="asdfasdf")

    #5 设置cookie生效路径
    path = ‘/‘

    #6 删除cookie中is_login的值
    response.delete_cookie(‘is_login‘)
    return response

设置cookie常用参数

  5、使用cookie实现用户登录、注销 

from django.shortcuts import render,HttpResponse,redirect

def index(request):
    username = request.COOKIES.get(‘username‘)        # 获取cookie
    if not username:
        return redirect(‘/login/‘)
    return HttpResponse(username)

def login(request):
    if request.method == "GET":
        return render(request,‘login.html‘)
    if request.method == "POST":
        u = request.POST.get(‘username‘)
        p = request.POST.get(‘pwd‘)
        if u == ‘tom‘ and p == ‘123‘:
            res = redirect(‘/index/‘)
            res.set_cookie(‘username‘,u,max_age=500)        # 设置500s免登陆
            return res
        else:
            return render(request,‘login.html‘)

def logout(req):
    response = redirect(‘/login/‘)
    #清理cookie里保存username
    response.delete_cookie(‘username‘)
    return response

views.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login/" method="POST">
        <input type="text" name="username" placeholder="用户名">
        <input type="text" name="pwd" placeholder="密码">
        <input type="submit" value="提交">
    </form>
</body>
</html>

login.html

  6、前端设置、获取cookie

from app01 import views
urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^index/‘, views.index),
    url(r‘^get_ck/‘, views.get_ck),
]

urls.py

from django.shortcuts import render,HttpResponse

def index(request):
    return render(request, ‘index.html‘, )

def get_ck(request):
    val = request.COOKIES.get(‘per_page_count‘)
    print(‘get_ck‘,val)
    return HttpResponse(val)

/app01/views.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {# 选择每页显示多少条的select单选框 #}
    <div>
        <select id="ps" onchange="changePageSize(this)">
            <option value="10">10</option>
            <option value="20">20</option>
            <option value="50">50</option>
            <option value="100">100</option>
        </select>
    </div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>

    <script>
        //当框架加载完成后获取cookie的值,并设置到select中
        $(function(){
           var v = $.cookie(‘per_page_count‘);     //前端获取cookie值
            console.log(v);
            $(‘#ps‘).val(v);
        });

        function changePageSize(ths){
            //获取select单选框选择的值(10,20,50,100)这些选项
            var v = $(ths).val();
            //使用cookie将v的值传递到后台
            $.cookie(‘per_page_count‘,v, { expires: 7 });        //前端设置cookie值
            $.cookie(‘per_page_count‘,v, {‘path‘:‘/‘});       // 将这个路径设置为网站的根目录
        }
    </script>
</body>
</html>

index.html

1.2 session

   1、Session作用 & 原理(session操作依赖cookie)

    1. 基于Cookie做用户验证时:敏感信息不适合放在cookie中

    2. 用户成功登陆后服务端会生成一个随机字符串并将这个字符串作为字典key,将用户登录信息作为value

    3. 当用户再次登陆时就会带着这个随机字符串过来,就不必再输入用户名和密码了

    4. 用户使用cookie将这个随机字符串保存到客户端本地,当用户再来时携带这个随机字符串,服务端根据

        这个随机字符串查找对应的session中的值,这样就避免敏感信息泄露

  2、Cookie和Session对比

    1、Cookie是保存在用户浏览器端的键值对

    2、Session是保存在服务器端的键值对

  3、Django中支持下面五种session,可以在settings.py中配置

# 1、SESSION_COOKIE_NAME = "sessionid"          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
# 2、SESSION_COOKIE_PATH = "/"                  # Session的cookie保存的路径(默认)
# 3、SESSION_COOKIE_DOMAIN = None                # Session的cookie保存的域名(默认)
# 4、SESSION_COOKIE_SECURE = False               # 是否Https传输cookie(默认)
# 5、SESSION_COOKIE_HTTPONLY = True              # 是否Session的cookie只支持http传输(默认)
# 6、SESSION_COOKIE_AGE = 1209600                # Session的cookie失效日期(2周)(默认)
# 7、SESSION_EXPIRE_AT_BROWSER_CLOSE = False     # 是否关闭浏览器使得Session过期(默认)
# 8、SESSION_SAVE_EVERY_REQUEST = False          # 是否每次请求都保存Session,默认修改之后才保存(默认)
                                                 # 10s 免登陆时,这里必须配置成True

5种session在settings.py中公用配置参数

#1 数据库(默认)   #将session数据保存到数据库中
SESSION_ENGINE = ‘django.contrib.sessions.backends.db‘

#2 缓存             #将session数据保存到缓存中
# 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
# ‘default‘是下面链接的缓存别名,也可以是另一缓存名‘db1‘
SESSION_ENGINE = ‘django.contrib.sessions.backends.cache‘
SESSION_CACHE_ALIAS = ‘default‘
CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.memcached.MemcachedCache‘,
        ‘LOCATION‘: [
            ‘172.19.26.240:11211‘,
            ‘172.19.26.242:11211‘,
        ]
    },
    ‘db1‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.memcached.MemcachedCache‘,
        ‘LOCATION‘: [
            ‘172.19.26.240:11211‘,
            ‘172.19.26.242:11211‘,
        ]
    },
}

#3 文件Session
# 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
# 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T把他当做session目录
SESSION_ENGINE = ‘django.contrib.sessions.backends.file‘
SESSION_FILE_PATH = os.path.join(BASE_DIR,‘cache‘)          #保存session的文件夹目录

#4 缓存+数据库Session        #默认到缓存中拿session数据,没有再到数据库中取
SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db‘

#5 加密cookie Session        #其实质使用的是cookie,将数据放到了客户端,但是数据经过了加密
SESSION_ENGINE = ‘django.contrib.sessions.backends.signed_cookies‘

settings.py中配置使用session五种方法

   4、操作session:设置、获取等

def index11(request):                #request.session中存放了所有用户信息
    #1 获取   Session中数据
    request.session[‘k1‘]
    request.session.get(‘k1‘,None)
    
    #2 设置
    request.session[‘k1‘] = 123
    request.session.setdefault(‘k1‘,123)    # 存在则不设置
    
    #3 删除
    del request.session[‘k1‘]               #删除某个键值对
    #删除某用户登录时在数据库生成的随机字符串的整条数据全部删除
    request.session.delete("session_key")
    
    #4 注销  当用户注销时使用request.session.clear()
    request.session.clear()         #这个短句相当于下面这个长句
    request.session.delete(request.session.session_key)
    
    #5 设置超时时间(默认超时时间两周)
    request.session.set_expiry("value")
    # 如果value是个整数,session会在些秒数后失效。
    # 如果value是个datatime或timedelta,session就会在这个时间后失效。
    # 如果value是0,用户关闭浏览器session就会失效。
    # 如果value是None,session会依赖全局session失效策略。
    
    # 所有 键、值、键值对
    request.session.keys()
    request.session.values()
    request.session.items()
    request.session.iterkeys()
    request.session.itervalues()
    request.session.iteritems()
    
    # 获取某个用户session的随机字符串(不常用)
    request.session.session_key
    
    # 将所有Session失效日期小于当前日期的数据删除(数据库中可以设置超时时间)
    request.session.clear_expired()
    
    # 检查 用户session的随机字符串 在数据库中是否存在(不常用)
    request.session.exists("session_key")

操作session方法

   5、session实现用户十秒免登陆,以及注销功能

       1. session默认使用数据库session,使用前必须先执行下面命令

        python manage.py makemigrations
          python manage.py migrate

    2. settings.py中配置每次用户访问都会推辞更新时间

        SESSION_SAVE_EVERY_REQUEST = True

    3. 实现10s免登陆关键步骤

        1) 设置session :  request.session[‘is_login‘] = True

        2) 设置10s超时:  request.session.set_expiry(10)

        3) 获取session :  request.session.get(‘is_login‘)

from django.shortcuts import render,HttpResponse,redirect

def index(request):
    if request.session.get(‘is_login‘):
        return render(request,‘index.html‘,{‘username‘:request.session.get(‘username‘)})
    else:
        return HttpResponse(‘滚‘)

def login(request):
    if request.method == ‘GET‘:
        return render(request,‘login.html‘)
    elif request.method == ‘POST‘:
        user = request.POST.get(‘user‘)
        pwd = request.POST.get(‘pwd‘)
        if user == ‘tom‘ and pwd == ‘123‘:
            #1 生成随机字符串
            #2 写到用户浏览器cookie
            #3 保存到session中
            #4 在随机字符串对应的字典中设置相关内容
            #5 有等号设置session键值对,没有等号获取键的值

            request.session[‘username‘]=user       #1 用户登录成功设置用户名

            request.session[‘is_login‘] = True     #2 登陆成功时可以设置一个标志

            if request.POST.get(‘rmb‘) == ‘1‘:     #3 当勾选checkbox框后设置10秒超时
                request.session.set_expiry(10)     #4 设置10s后超时,需要重新登录
            return redirect(‘/index‘)
        else:
            return render(request,‘login.html‘)

def logout(request):
    request.session.clear()                         #5 访问‘/logout/‘时注销登陆
    return redirect(‘/login/‘)

views.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login/" method="POST">
        <input type="text" name="user">
        <input type="text" name="pwd">
        <input type="checkbox" name="rmb" value="1">十秒免登陆
        <input type="submit" value="提交">
    </form>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>欢饮登陆:{{ username }},{{ request.session.username }}</h1>
    <a href="/logout/">注销</a>
</body>
</html>

index.html

SESSION_SAVE_EVERY_REQUEST = True

settings.py

1.3 Django序列化操作

  1、为什么需要需要序列化操作

    1. python中很多格式的数据类型不能通过简单的json直接序列化转换成字符串格式传递到前端

    2. 比如:form提交出现错误,返回的是Django的errors.dict对象,不能直接用python的json序列化(必须先as_json)

  2、Django序列化(法1:前端两次序列化得到错误信息)

    1. 首先后端现用 as_json 将errors.dict对象转换成字符串,然后通过json传递到前端

    2. 前端第一次序列化:将整个错误信息大字典变成对象,提取到其中的error小字典

    3. 前端第二次序列化:由于获取的小字典是字符串,还需要将error序列化成对象,才能获取到错误信息

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields         #fields字段专门用于验证
from django.forms import widgets        #widgets专门用于生成html标签
import json

#这里为了方便没有将创建form放到forms.py中
class LoginForm(forms.Form):
    username = fields.CharField()
    password = fields.CharField(
        max_length=12,
        min_length=4,
        error_messages={
            ‘required‘:‘密码不能为空‘,
            ‘min_length‘:‘密码长度不能小于4‘,
            ‘max_length‘:‘密码长度不能大于12‘
        }
    )

def login(request):
    if request.method == ‘GET‘:
        return render(request,‘login.html‘)
    elif request.method == ‘POST‘:
        ret = {‘status‘:True,‘error‘:None,‘data‘:None}
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            #正确信息:{‘password‘: ‘1234567343434343434‘, ‘username‘: ‘tom‘}
        else:
            # obj.errors中封装的数据必须变成字符串才能json操作
            ret[‘error‘] = obj.errors.as_json()    # as_json() 返回的是字符串
            # print(obj.errors.as_data())
        return HttpResponse(json.dumps(ret))

views.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm">
        {% csrf_token %}
        <p><input type="text" name="username"></p>
        <p><input type="password" name="password">
            <span id="pwd-err" style="color: red"></span></p>
        <a id="submit">ajax提交</a>
    </form>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        /*  #### 当不填密码提交后返回的错误信息时这样的  ####
        {‘status‘: True,
        ‘error‘: ‘{"password": [{"code": "required", "message": "密码不能为空"}]}‘,
        ‘data‘: None}
         */

        $(function(){
            $(‘#submit‘).click(function(){
                $.ajax({
                    url: ‘/login/‘,
                    type:‘POST‘,
                    data:$(‘#fm‘).serialize(),
                    success:function(arg){              // 服务端返回的arg是字符串格式

                        arg = JSON.parse(arg);          // 第一次json转换:将arg字符串转换成对象

                        error = arg.error;             // 获取到arg对象中的error(error此时是字符串)

                        error = JSON.parse(error);      // 第二次json转换:将error字符串转换成对象

                        pwd_err = error.password[0].message;     // 转换成对象后才能获取到最终的错误信息
                        console.log(pwd_err);                     //pwd_err打印结果:密码不能为空
                        $(‘#pwd-err‘).text(pwd_err);
                    },
                    error:function(){
                    }
                })
            })
        })
    </script>
</body>
</html>

login.html

   3、Django序列化(法2:前端一次序列化得到错误信息)

    1. 首先后端 as_data() 将获取到错误数据

    2. 然后将数据放到JsonCustomEncoder类中转换成指定格式的字典,前端一次即可的到错误提示信息

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields        #fields字段专门用于验证
from django.forms import widgets       #widgets专门用于生成html标签
import json

from django.core.exceptions import ValidationError
class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, ValidationError):
            return {‘code‘:field.code,‘messages‘:field.messages}
        else:
            return json.JSONEncoder.default(self, field)

#这里为了方便没有将创建form放到forms.py中
class LoginForm(forms.Form):
    username = fields.CharField()
    password = fields.CharField(
        max_length=12,
        min_length=4,
        error_messages={
            ‘required‘:‘密码不能为空‘,
            ‘min_length‘:‘密码长度不能小于4‘,
            ‘max_length‘:‘密码长度不能大于12‘
        }
    )

def login(request):
    if request.method == ‘GET‘:
        return render(request,‘login.html‘)
    elif request.method == ‘POST‘:
        ret = {‘status‘:True,‘error‘:None,‘data‘:None}
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            #正确信息:{‘password‘: ‘1234567343434343434‘, ‘username‘: ‘tom‘}
        else:
            # obj.errors中封装的数据必须变成字符串才能json操作
            ret[‘error‘] = obj.errors.as_data()     # as_json() 返回的是字符串
            # print(obj.errors.as_data())           # {‘password‘: [ValidationError([‘密码不能为空‘])]}
            print(ret)
        request = json.dumps(ret,cls=JsonCustomEncoder)
        print(request)
        return HttpResponse(request)

views.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm">
        {% csrf_token %}
        <p><input type="text" name="username"></p>
        <p><input type="password" name="password">
            <span id="pwd-err" style="color: red"></span></p>
        <a id="submit">ajax提交</a>
    </form>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function(){
            $(‘#submit‘).click(function(){
                $.ajax({
                    url: ‘/login/‘,
                    type:‘POST‘,
                    data:$(‘#fm‘).serialize(),
                    success:function(arg){                //服务端返回的是字符串格式

                        arg = JSON.parse(arg);            //这里只需要一次序列化就可以得到error字典格式

                        pwd_err = arg.error.password[0].messages;

                        console.log(pwd_err);            //pwd_err打印结果:密码不能为空
                        $(‘#pwd-err‘).text(pwd_err);
                    },
                    error:function(){
                    }
                })
            })
        })
    </script>
</body>
</html>

index.html

1.4 CSRF跨站请求伪造

  1、CSRF原理

    1、当用户第一次发送get请求时,服务端不仅给客户端返回get内容,而且中间包含一个随机字符串
      2、这个字符串是加密的,只有服务端自己可以反解
      3、当客户端发送POST请求提交数据时,服务端会验证客户端是否携带这个随机字符串, 没有就会引发csrf错误

    4、如果没有csrf,那么黑客可以通过任意表单向我们的后台提交数据,不安全

  2、form和ajax提交数据 解决CSRF方法

    1、$.cookie(‘csrftoken‘)可以获取到那个随机字符串

    2、headers{} 可以将指定信息添加到请求头部发送给服务端

    3、通过cookie和通过{{ csrf_token }}获取的随机字符串不同

<form action="/login/" method="POST">

    {#1 form方式提交仅需要在form表单中添加csrf_token生成随机字符串即可 #}
    {% csrf_token %}

    <input type="submit" name="提交">
    <input id="btn" type="button" value="按钮">
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>

    {#2 使用ajax提交CSRF字符串的两种方法 #}
<script>
    $(function(){

    {# 方法一: 仅用定义一个ajaxSetup实现对所有页面ajax提交数据自动发送CSRF字符串 #}
        //xhr是ajax内部封装的一个方法
        $.ajaxSetup({
           beforeSend:function(xhr,settings){
                xhr.setRequestHeader(‘X-CSRFtoken‘,$.cookie(‘csrftoken‘))
           }
        });

    {# 方法二: 必须在每个ajax提交的函数中都指定要发送CSRF字符串 #}
        $(‘#btn‘).click(function(){
            $.ajax({
                url: ‘/login/‘,
                type: ‘POST‘,
                data: {‘user‘:‘root‘,‘pwd‘:‘123‘},
                headers:{‘X-CSRFtoken‘:$.cookie(‘csrftoken‘)},
                success:function(data){
                }
            })
        })
    })
</script>

from和ajax提交数据 解决CSRF方法

   3、ajax提交过滤

    说明:对以GET,HEAD,OPTIONS,TRACE这四种提交数据方法不提交CSRF字符串

<script>
    var csrftoken = $.cookie(‘csrftoken‘);
    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });
</script>

ajax提交过滤

  4、指定那些函数启用CSRF验证

#1 启用settings文件中的CSRF

MIDDLEWARE = [
    ‘django.middleware.csrf.CsrfViewMiddleware‘,
]

#2 对不需要验证的函数添加@csrf_exempt

from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt
def login(request):
    ‘处理函数内容‘

法1:启用CSRF验证指,仅指定某些页面不需要验证

#1 关闭settings文件中的CSRF

MIDDLEWARE = [
    # ‘django.middleware.csrf.CsrfViewMiddleware‘,
]

#2 对需要验证的函数添加@csrf_protect

from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_protect
def login(request):
    ‘处理函数内容‘

法2:关闭CSRF验证指,仅指定某些页面需要验证

1.5 信号

  1、信号作用

    1. Django中提供了“信号调度”,用于在框架执行操作时解耦。

    2. 通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。

    3. 比如我们在删除数据时需要记录删除了什么就可以使用信号

  2、Django内置信号

    作用:Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。

    1. Django内置信号

1、    Model signals
#1  obj = models.UserInfo(user=‘root‘) django的modal执行其构造方法
#2  obj.save()    django的modal对象保存
    pre_init                 # django的modal执行其构造方法前,自动触发
    post_init                # django的modal执行其构造方法后,自动触发
    pre_save                 # django的modal对象保存前,自动触发
    post_save                # django的modal对象保存后,自动触发

    pre_delete               # django的modal对象删除前,自动触发
    post_delete              # django的modal对象删除后,自动触发
    m2m_changed              # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared           # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
    
2、Management signals
    pre_migrate              # 执行migrate命令前,自动触发
    post_migrate             # 执行migrate命令后,自动触发
    
3、Request/response signals
    request_started          # 请求到来前,自动触发
    request_finished         # 请求结束后,自动触发
    got_request_exception    # 请求异常后,自动触发
    
4、Test signals
    setting_changed          # 使用test测试修改配置文件时,自动触发
    template_rendered        # 使用test测试渲染模板时,自动触发
    
5、Database Wrappers
    connection_created       # 创建数据库连接时,自动触发

Django内置信号

     2. 使用Django内置信号(当Django新建数据时自动触发某函数)

    1、首先在Django工程目录下新建sg.py,将Django中所有内置信号全部导入到里面
      2、在project/__init__.py中导入sg.py (作用:当Django一运行就自动导入所有信号)
      3、在views.py中定义single函数,执行obj = models.UserInfo(user=‘root‘) 测试

#1 导入Django中内置信号
from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception
from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created

#2 定义一个函数以便内置信号触发时调用
def f1(sender, **kwargs):
    print("xxoo_callback")

#3 将自己定义的函数注册到Django内置信号中
pre_init.connect(f1)      #将f1注册到这里,每次执行modal构造方法前,自动触发

#4 xxoo.connect(callback)   xxoo指上述导入的内容

project/sg.py定义信号及触发的函数

import sg

project/__init__.py导入sy.py模块

def signal(request):
    from app01 import models
    print(‘start‘)
    obj = models.UserInfo(user=‘root‘)
    print(‘end‘)
    obj.save()
    return HttpResponse(‘111‘)

project/views.py中触发信号

   3、自定义信号

    说明:由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发

#1  pizza_done是自己定义的信号名称
#2 ["toppings", "size"]指定要想触发这个信号必须传递这两个参数
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

#3 定义一个函数
def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)

#4 将上面定义的函数注册到我们自定义的信号中
pizza_done.connect(callback)

project/sg.py自定义信号

import sg

project/__init__.py导入sy.py模块

def signal(request):
    from sg import pizza_done
    pizza_done.send(sender=‘suifasongde‘,toppings=‘suibianxie‘,size=‘suibianxie‘)

    return HttpResponse(‘111‘)

project/views.py中触发信号

1.6 Django中的缓存

  1、Django缓存作用

    1. 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显

    2. 缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作

    3. 而是直接从内存或者Redis中之前缓存的内容拿到,并返回

  2、Django中提供了6种缓存方式

# 开发调试缓存(虽然配置上,但实际没有缓存,还是到数据库取)

CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.dummy.DummyCache‘,  # 引擎

        #注: 下面这些参数时公用的,五种缓存都可以使用
        ‘TIMEOUT‘: 300,           # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
        ‘OPTIONS‘:{
            ‘MAX_ENTRIES‘: 300,   # 最大缓存个数(默认300)
            ‘CULL_FREQUENCY‘: 3,  # 缓存到达最大个数之后,剔除缓存个数的比例(3就是1/3)
        },
    }
}

1:开发调试缓存

# 注:内存缓存本质上就是在内存中维护一个字典,所存储的形式就是字典的键值对组合

CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.locmem.LocMemCache‘,
        ‘LOCATION‘: ‘unique-snowflake‘,     #这个参数指定变量名必须唯一
    }
}

2:内存缓存

CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.filebased.FileBasedCache‘,
        ‘LOCATION‘: os.path.join(BASE_DIR,‘cache‘),  #缓存内容存放的文件夹路径
    }
}

3:文件缓存

# 注:执行创建表命令 python manage.py createcachetable

CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.db.DatabaseCache‘,
        ‘LOCATION‘: ‘my_cache_table‘, # 数据库表名(名字是自己取的)
    }
}

4:数据库缓存

# 注:Memcache缓存有两个模块:python-memcached模块、 pylibmc模块


CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.memcached.MemcachedCache‘,
        ‘LOCATION‘: ‘127.0.0.1:11211‘,          #使用ip加端口连接memcached
    }
}

CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.memcached.MemcachedCache‘,
        ‘LOCATION‘: ‘unix:/tmp/memcached.sock‘,     #以文件的形式连本地memcached
    }
}

CACHES = {
    ‘default‘: {
        ‘BACKEND‘: ‘django.core.cache.backends.memcached.MemcachedCache‘,
        ‘LOCATION‘: [               # memcached天生支持集群
            #1 均衡分配
            ‘172.19.26.240:11211‘,
            ‘172.19.26.242:11211‘,
            #2 调整权重(权重和请求比例成正比)
            (‘172.19.26.240:11211‘,1),
            (‘172.19.26.242:11211‘,10),
        ]
    }
}


# 注: pylibmc模块只改变上面‘BACKEND‘配置为下面样式即可
# ‘BACKEND‘: ‘django.core.cache.backends.memcached.PyLibMCCache‘,

5:Memcache缓存 两种

  3、Django中缓存3种应用

    1. 页面级别缓存(需要在views.py文件中引入cache_page

# 1、views.py文件中的处理函数

from django.views.decorators.cache import cache_page
@cache_page(6)                 #6秒后缓存失效
def cache(request):
    import time
    ctime = time.time()
    return render(request,‘cache.html‘,{‘ctime‘:ctime})
    
# 2、cache.html文件中内容都会被缓存,5s后才会失效

<body>
    <h1>{{ ctime }}</h1>      #页面刷新时时间不会时刻变化,5s过后才会变一次
</body>

页面级别缓存

    2. 模板级别缓存(直接在cache.html模板文件中指定某个值放入缓存)

{#1 在文件最顶部引入TemplateTag#}
{% load cache %}

<body>
    {#2 使用缓存   c1是缓存的key值 #}
    {% cache 5 c1 %}        {# 将数据缓存5秒 #}
        {{ ctime }}
    {% endcache %}
</body>

模板级别缓存

    3. 全局缓存(只需要在settings.py中间件配置的首尾各加一条)

        注:设置全局缓存后所有页面的模板数据都会应用

MIDDLEWARE = [
        ‘django.middleware.cache.UpdateCacheMiddleware‘,
        # 其他中间件...
        ‘django.middleware.cache.FetchFromCacheMiddleware‘,
]

全局缓存

相关推荐