Django信号,缓存,权限系统

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

信号适用场景:比如监控阀值,可以让做某个操作。比如运维监控,当触发到阀值,发短信,邮件等报警。

django在对象创建保存预留了4个钩子,可以用来操作,即可以对象创建保存时候调用内置信号,触发其他动作。

obj=models.UserInfo(name="name") django在这前后刘了两个钩子 这里是model一个构造方法  
obj.save()django在这前后刘了两个钩子

Django内置信号

Model signals
    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类,对于每一个类,自动触发
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发

对于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


    def callback(sender, **kwargs):
        print("xxoo_callback")
        print(sender,kwargs)

    xxoo.connect(callback)
    # xxoo指上述导入的内置信号

基于装饰器实现:

我们要做的,就是注册一个receiver函数。例如,如果要在每次请求完成之后,打印一行字。
可以使用回调的方式注册:

# receiver
def my_callback(sender, **kwargs):
  print("Request finished!")
  
# connect
from django.core.signalsimport request_finished 
request_finished.connect(my_callback)
也可以使用装饰器的方式注册,下面这段代码和上面完全是等价的。 from django.core.signalsimport request_finished from django.dispatchimport receiver @receiver(request_finished) def my_callback(sender, **kwargs): print("Request finished!")

自定义信号

定义信号

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

注册信号

def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)
  
pizza_done.connect(callback)

触发信号

from 路径 import pizza_done
  
pizza_done.send(sender='seven',toppings=123, size=456)

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

示例:

 1)内置信号使用

 2)自定义信号

#urls.py

from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^user_add/', views.user_add),
]

#models.py
class User(models.Model):
    username=models.CharField(max_length=32)
    password=models.CharField(max_length=32)

#自定义信号sg.py
# -*- coding:utf-8 -*-
__author__ = 'shisanjun'
import django.dispatch
#自定义信号pizza_done
pizza_done=django.dispatch.Signal(providing_args=["name","pwd"])#name和pwd是自定义传递的参数

#在同工程名__init__.py
import sg
#如果这里不导入,使用自定义信号报错



#views.py
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
#自定信号模块
import sg
def my_callback_post_save(*args,**kwargs):
    print("保存数据后触发的信号。。。后。。")

def my_callback_pre_save(*args,**kwargs):
    print("保存数据前触发的信号。。。前。。")

#保存数据后出触发信号 导入
from django.db.models.signals import post_save,pre_save

pre_save.connect(my_callback_pre_save)
post_save.connect(my_callback_post_save)

#自定义信号pizza_done的回调函数
def my_callback(sender,*args,**kwargs): #sender是必须有的参数
    print("自定义信号",sender,kwargs)

#给自定信号pizza_done增加回调函数
sg.pizza_done.connect(my_callback)

def user_add(request):

    # user_obj=models.User(username="root",password="123")
    # print("save before")
    # user_obj.save()
    # #给信号注册回调函数
    # print("save end")
    models.User.objects.create(username="root",password="123")

    #手动触发自定义信号
    sg.pizza_done.send(sender="semder",name="root",pwd="123")
    return HttpResponse("OK")
结果:
  保存数据前触发的信号。。。前。。
  [19/Nov/2017 11:30:16] "GET /user_add/ HTTP/1.1" 200 2
  保存数据后触发的信号。。。后。。
  自定义信号 semder {'signal': <django.dispatch.dispatcher.Signal object at 0x0000000003F2B278>, 'name': 'root', 'pwd': '123'}

二:Django缓存机制(只写以后常用的缓存配置以及应用)

# 配置:(写在配置文件里)

①缓存存储在文件中

CACHES = {
'default': {
  'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', #引擎
  'LOCATION': '/var/tmp/django_cache',
  'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
  'OPTIONS':{
    'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
    'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
  },
  'KEY_PREFIX': '', # 缓存key的前缀(默认空)
  'VERSION': 1, # 缓存key的版本(默认1)
  'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
  }
  }

②缓存按照分布式存储在内存中

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
或者
# 此缓存使用pylibmc模块连接memcache
   CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
应用有三种:
①使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
  MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',(该中间件在第一层,用于从后端获取未缓存的数据再存入缓存中)
        # 其他中间件...
        'django.middleware.cache.FetchFromCacheMiddleware',(该中间件在最后一层,用于查找缓存)
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""
②单独视图缓存
 方式一:
        from django.views.decorators.cache import cache_page

        @cache_page(60 * 15)
        def my_view(request):
            ...

    方式二:
        from django.views.decorators.cache import cache_page

        urlpatterns = [
            url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
        ]
③局部视图使用缓存(模板语言)
  a. 引入TemplateTag

        {% load cache %}

    b. 使用缓存

        {% cache 5000 缓存key %}
            缓存内容
        {% endcache %}
三:序列化
def get_data(request):(视图函数中的get_data函数)
# 方案一:
    ####################################################################################################################
    #对于方案一,因为使用的是objects.all(对象的操作方法),所以无法连表,也就是说serializer只可以支持单表的序列化
    # queryset[UserInfo对象,]
    # user_list = models.UserInfo.objects.all()
    # from django.core import serializers
    # user_list_str = serializers.serialize("json", user_list)
    # return HttpResponse(user_list_str)

# 方案二: ################################################################################################################### #对于方案二,由于使用的是values方法,可以实现连表操作,所以json.dumps,cls=...可以实现跨表查询以及查询结果的序列化, # 使用起来更加便捷以及实用 # querset=[{},{},{}] user_list = models.UserInfo.objects.values('name','pwd') user_list = list(user_list) #cls是json自带的一个处理类,对于无法处理的datetime类型,可以在继承json.JSONEncoder的基础上自定义default方法。 val = json.dumps(user_list,cls=json.JSONEncoder) return HttpResponse(val)
四:与性能有关的数据库查询
数据库表关系如下:
from django.db import models

class UserType(models.Model):
    caption = models.CharField(max_length=32)

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=64)
    ut = models.ForeignKey(to='UserType',to_field='id',null=True,blank=True)
这里是视图函数:
def index(request):(视图函数中的index函数)
    # [obj,obj,obj]
    # 查询用户表models.UserInfo.objects.all() 1000
    # 把用户表中所有的ut_id拿到, 用户类型ID [1,2,3]
  再去拿对应外键的表的所有对象组成的Queryset(这两个步骤对应prefetch_related查询方法)
  对于select_related则是根据外键将两张表连接起来进行连表查询
  
    # select * from UsetType where id in [1,2,3]
    # user_list = models.UserInfo.objects.all().prefetch_related('ut')
    # for row in user_list:
    #     print(row.name, row.pwd, row.ut.caption)



    # for row in user_list:
    #     print(row.name,row.pwd,row.ut.caption)
    #
    # # [{},{},{}]
    # user_list = models.UserInfo.objects.values('name','pwd','ut__caption')
    # for row in user_list:
    #     print(row['name'],row['pwd'],row['ut__caption'])

    # [obj,obj,obj]
    # user_list = models.UserInfo.objects.all().only('name')
    user_list = models.UserInfo.objects.all().defer('name')
    for row in user_list:
        print(row.pwd)


    return render(request,'index.html',{'user_list':user_list})

 

 

 

posted on 2018-01-10 11:11  龚旭1994  阅读(267)  评论(0编辑  收藏  举报