zoukankan      html  css  js  c++  java
  • Django信号和缓存

     一、Django的缓存

     缓存了解:

     对于运维来说缓存应该是不难理解的。不管是从公司平台运维,还是到CDN运维。都会用到缓存。那为什么需要缓存呢?缓存的主要用处——就是在某一个地方将想缓存的页面保存起来。在用户下一次访问该页面的时候就可以直接从缓存中取数据,这样就减少了客户端请求和web服务器的逻辑运算。

     回到Django。我们都知道Django建立的是动态网站,正常情况下,每次请求过来都经历了这样一个过程:接收请求 -> url路由 -> 视图处理 -> 数据库读写 -> 视图处理 -> 模版渲染 -> 返回请求。

      设想这么个场景,一个用户或者大量用户都对某个页面非常感兴趣,出现了大量实质相同的请求,如果每次请求都采取上面的流程,将出现大量的重复工作,尤其是大量无谓的数据库读写。

      要解决这个问题,有很多办法,其中一个就是使用缓存。

      缓存的思路是,既然已经处理过一次,得到了结果,就把当前结果缓存下来。下次再请求时,把缓存的处理结果直接返回。这样,可以极大地减少重复工作,降低数据库负载。

     Django中提供的6中缓存方式:

    • 开发调试
    • 内存
    • 文件
    • 数据库
    • memcached

     开发用的缓存
      Django很贴心的为我们设计了一个开发用的缓存。当你的生产环境是个大型的缓存系统,而你在开发的时候又没有相应的缓存系统支持,或者不想用那种笨重的大家伙进行开发。但实际开发过程中,你又不得不接入缓存系统,使用缓存的api,这种情况下,开发用的缓存就很顺手了。

    配置如下:

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',  # 引擎
            'TIMEOUT': 300,  # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
            'OPTIONS': {
                'MAX_ENTRIES': 300,  # 最大缓存个数(默认300)
                'CULL_FREQUENCY': 3,  # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
            }
        }
    }

     基于本地内存的缓存
      如果你的本地主机内存够大够快,也可以直接使用它作为缓存。配置如下:

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
            'LOCATION': 'unique-snowflake', #保存的内存中的变量名称
        }
    }

     文件系统缓存
    连数据库我们都觉得慢,那么基于文件系统的呢?更慢!不过在你手里没有Redis、Memcached和数据库的时候,也可以勉为其难的用一下。下面给出两个配置案例:

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'LOCATION': '/var/tmp/django_cache',
        }
    }

     数据库缓存
    我们使用缓存的很大原因就是要减少数据库的操作,如果将缓存又存到数据库,岂不是脱....
    所以,尽量不要使用基于数据库的缓存,这里也不做具体介绍,给个简单的配置范例吧:

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
            'LOCATION': 'my_cache_table',
        }
    }

     

     Memcached

      Memcached是Django原生支持的缓存系统,速度快,效率高。Memcached是一种基于内存的缓存服务,起初是为了解决LiveJournal.com的负载问题而开发的,后来由Danga开源。 它被类似Facebook和维基百科这种大型网站使用,用来减少数据库访问次数,显著地提高了网站的性能。

      Memcached会启动一个守护进程,并分配单独的内存块。其主要工作就是为缓存提供一个快速的添加,检索,删除的接口。所有的数据直接存储在内存中,所以它不能取代数据库或者文件系统的功能。如果你对缓存很熟悉,这些内容都很好理解。

    如果你是新手,那么要清楚:

    • Memcached不是Django自带的软件,而是一个独立的软件,需要你自己安装、配置和启动服务;
    • Memcached安装好了后,还要安装Python操作Memcached的依赖库,最常用的是python-memcached和pylibmc;
    • 上面两个条件都满足了后,还要在Django中进行配置。

     配置方法:

    • 根据你安装的Python依赖库不同,将CACHES的BACKEND设置为django.core.cache.backends.memcached.MemcachedCache或者django.core.cache.backends.memcached.PyLibMCCache
    • 设置LOCATION为你的Memecached守护进程所在的主机IP和进程端口,格式为ip:port的字符串。或者unix:path的形式,在Unix操作系统中。

    下面是一个参考例子,Memcached运行在localhost (127.0.0.1) port 11211,使用了python-memcached库:

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

      下面的Memcached运行在本地的Unix socket上:/tmp/memcached.sock,依赖python-memcached

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

     Memcached支持分布式服务,可能同时在几台机器上运行,将它们的IP地址都加入到LOCATION中,如下所示:

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:21423',
                '172.19.26.244:11213',
            ]
        }
    }

      基于内存的缓存系统有个明显的缺点就是断电数据丢失,尤其是Memcached这种不支持序列化的缓存,所以请大家务必要注意数据的安全性。

      其实对于当下,redis如日中天的时代,还是选择redis作为缓存吧,还支持序列化,不过Django默认是不支持redis的,需要自己定制。

      缓存参数

     上述每一个缓存后端都可以设置一些额外的参数来控制缓存行为,可以设置的参数如下:

    • TIMEOUT

     缓存的默认过期时间,以秒为单位,默认是300秒None表示永远不会过期。设置成0将造成缓存立即失效(缓存就没有意义了)。

    • OPTIONS

       可选参数,根据缓存后端的不同而不同。

    • KEY_PREFIX

     Django服务器使用的所有缓存键的字符串。

    • VERSION

     由Django服务器生成的默认版本号。

    • KEY_FUNCTION

      一个字符串,其中包含一个函数的点路径,该函数定义了如何将前缀,版本和密钥组合成最终缓存密钥。

     缓存全站

      缓存系统最简单的使用方法是缓存整个网站。

      这需要额外将'django.middleware.cache.UpdateCacheMiddleware'和'django.middleware.cache.FetchFromCacheMiddleware'添加到MIDDLEWARE设置中,如下所示:

    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

     缓存视图

      另一个使用缓存框架的方法是对视图的输出进行缓存。在django.views.decorators.cache定义了一个自动缓存视图响应结果的装饰器cache_page,使用非常简单:

    from django.views.decorators.cache import cache_page
    
    @cache_page(60)
    def index(request):
        ...

      cache_page接受一个参数:timeout,秒为单位。在上例中,my_view()视图的结果将被缓存1分钟(为了提高可读性写成了60)

     缓存模板片段

      我们还可以使用cache模板标签来缓存模板的一个片段。要使用这个标签,首先要在模版的顶部位置添加{% load cache %}

      模板标签{% cache %}将在设定的时间内,缓存标签块中包含的内容。它最少需要两个参数:缓存时间(以秒为单位)以及给缓存片段起的名称。像这样:

    {% load cache %}
    {% cache 500 sidebar %}
        .. sidebar ..
    {% endcache %}

      还可以依据片段内的动态内容缓存多个版本。如上个例子中,可以给站点的每个用户生成不同版本的sidebar缓存。 只需要给{% cache %}标签再传递一个参数来标识区分这个缓存片段,如下所示:

    {% load cache %}
    {% cache 500 sidebar request.user.username %}
        .. sidebar for logged in user ..
    {% endcache %}

     Django的序列化

     关于后台数据格式类型(一)

      目的:通过ajax取回我们所需要的网页信息

      首先我们先看下URL路由映射关系

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index.html',views.index), #直接通过后台取到所有值,然后交给前段渲染
        url(r'^show.html',views.show), #通过ajax取值
        url(r'^get_data',views.get_data), #取到的值
    ]

      视图函数

    def show(request): #知识返回了一个空的页面,不过在页面中有ajax提交数据
    
        return render(request,'show.html',locals())
    
    def get_data(request): #通过ajax获取到的数据
        user_list = models.UserInfo.objects.all()
        print(user_list)
        # return HttpResponse('...None')
        return render(request,'tpl.html',{'user_list':user_list})

      最后来看下一我们的template

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="/static/jquery-1.12.4.js"></script>
    </head>
    <body>
        <div  id="content"></div>
        <script>
            $(function () {
                $.ajax({
                    url: '/get_data/',
                    type: 'GET',
                    success:function (data) {
                        $('#content').append(data);
                        console.log(data)
                    }
                })
            })
        </script>
    </body>
    </html>
    视图show返回的template
    <ul>
        {% for row in user_list %}
            <span><li>r{{ row.username }}</li>  <li>r{{ row.pwd }}</li></span>
    
        {% endfor %}
    
    </ul>
    视图get_data返回的template

     关于后台数据格式类型(二)

      上面实例中ajax与后台交互的时候返回的是一个已经处理好数据的HTML页面,下面这一种方式是直接给前段返回一个json序列化好的数据,看一看前段如何渲染

      URL路由以映射关系

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index.html',views.index),
        url(r'^show.html',views.show),
        url(r'^get_data',views.get_data),
    ]

      视图函数

    def show(request):
    
        return render(request,'show.html',locals())
    
    def get_data(request):
        user_list = models.UserInfo.objects.all()
        user_list = [
            {'id':1,'name':'xx','pwd':123 },
            {'id':2,'name':'xx','pwd':123 },
            {'id':3,'name':'xx','pwd':123 },
            {'id':4,'name':'xx','pwd':123 },
        ]
        # return HttpResponse('...None')
        # return render(request,'tpl.html',{'user_list':user_list})
        return HttpResponse(json.dumps(user_list))

     template

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="/static/jquery-1.12.4.js"></script>
    </head>
    <body>
        <div  id="content">
            <ul></ul>
        </div>
        <script>
            $(function () {
                $.ajax({
                    url: '/get_data/',
                    type: 'GET',
                    success:function (data) {
                        //$('#content').append(data);
                        data = JSON.parse(data);
                        $.each(data,function (i,row) {
                            var tag = document.createElement('li');
                            tag.innerHTML = row.name;
                            $('#content ul').append(tag)
                        })
                    }
                })
            })
        </script>
    </body>
    </html>

     Django序列化数据

      Django的序列化工具让你可以将Django的模型‘翻译’成其它格式的数据。通常情况下,这种其它格式的数据是基于文本的,并且用于数据交换传输过程。其主要的目的就是为了序列化从models操作得到的QuerySet类型的对象。

      Django为我们提供了一个强大的序列化工具serializers。使用它也很简单,如下所示:

    from django.core import serializers
    
    data = serializers.serialize('json',models.UserInfo.objects.all())

       首先,从djang.core导入它,然后调用它的serialize方法,这个方法至少接收两个参数,第一个是你要序列化成为的数据格式,这里是‘json’,第二个是要序列化的数据对象,数据通常是ORM模型的QuerySet,一个可迭代的对象。

     ajax解决CSRFtoken问题

      在使用ajax对后端提交post请求的时候,如果在不注释掉settings.py中CSRF行。我们的数据是提交不到后台的,因为在数据经过中间件CSRFtoken时,会抛出一个403的错误。这个错误就是由于ajax在提交数据的时候没有带上CSRFtoken。

     第一种解决方案:

      手动找到csrftoken的标签,然后将数据带到后台。

    $.ajax({
        url: '/post_url',
        type: 'POST',
        data: {'username':'leon','password':'123123','csrfmiddlewaretoken':$('input[name='csrfmiddlewaretoken']')},
        dataType: 'JSON',
        success:function(args){
            // args is server return data
        }
    })

     第二种解决方案:

      使用form表单将所有数据封装起来发送到后台

    $.ajax({
        url: '/post_url',
        type: 'POST',
        data: #('form_id').serialize(),
        dataType: 'JSON',
        success:function(args){
            // args is server return data
        }
    })

     第三种解决方案

      cookie中获取csrftoken的信息

     django信号

    放到

  • 相关阅读:
    Java面试基础 -- Git篇
    Java面试基础
    如何避免死锁?
    如何减少上下文切换?
    Java中的volatile变量有什么作用?
    Thread类中start()方法喝run()方法有什么不同?
    (一)java异常处理的几个问题
    SUSE CaaS Platform 4
    SUSE CaaS Platform 4
    SUSE Ceph 增加节点、减少节点、 删除OSD磁盘等操作
  • 原文地址:https://www.cnblogs.com/yanlinux/p/9151434.html
Copyright © 2011-2022 走看看