zoukankan      html  css  js  c++  java
  • 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})
    
    
    
     
  • 相关阅读:
    JMeter递增加压总结
    JMeter跨线程传参总结
    JMeter+Grafana+Influxdb可视化性能监控平台搭建总结
    MONyog入门总结
    MongoDB导出/导入操作
    测试工作中用到的MongoDB命令
    Go单元测试与报告
    Postwoman教程
    测试工作中用到的Redis命令
    redis-dump教程
  • 原文地址:https://www.cnblogs.com/gongxu/p/8257539.html
Copyright © 2011-2022 走看看