天天看點

第25天,Django之緩存、序列化、信号

目錄

一、緩存
    1. 配置
        1.1 開發調試
        1.2 記憶體
        1.3 檔案
        1.4 資料庫
        1.5 Memcache緩存(python-memcached子產品)
        1.6 Memcache緩存(pylibmc子產品)
    2. 緩存應用
        2.1 站點級緩存
        2.2 單個視圖緩存
        2.3 模闆片段緩存
二、序列化
    1、serializers
    2、json.dumps
三、信号
    1. Django内置信号
           

一、緩存

由于Django是動态網站,所有每次請求均會去資料進行相應的操作,當程式通路量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存将一個某個views的傳回值儲存至記憶體或者memcache中,5分鐘内再有人來通路時,則不再去執行view中的操作,而是直接從記憶體或者Redis中之前緩存的内容拿到,并傳回。

Django中提供了6種緩存方式:

  • 開發調試
  • 記憶體
  • 檔案
  • 資料庫
  • Memcache緩存(python-memcached子產品)
  • Memcache緩存(pylibmc子產品,隻是與上面換了個子產品而已)

1. 配置

1.1 開發調試

# 此為開始調試用,實際内部不做任何操作
    # 配置:
        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)
                },
                'KEY_PREFIX': '',                                             # 緩存key的字首(預設空)
                'VERSION': 1,                                                 # 緩存key的版本(預設1)
                'KEY_FUNCTION' 函數名                                          # 生成key的函數(預設函數會生成為:【字首:版本:key】)
            }
        }


    # 自定義key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func
           
注意:如果不需要自定義緩存的key,可以不用寫KEY_PREFIX、VERSION、KEY_FUNCTION以及自定義key的函數。

1.2 記憶體

# 此緩存将内容儲存至記憶體的變量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'unique-snowflake',
            }
        }

    # 注:其他配置同開發調試版本
           

1.3 檔案

# 此緩存将内容儲存至檔案
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
                'LOCATION': '/var/tmp/django_cache',
            }
        }
    # 注:其他配置同開發調試版本
           

1.4 資料庫

# 此緩存将内容儲存至資料庫

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 資料庫表
            }
        }

    # 注:執行建立表指令 python manage.py createcachetable
           

使用資料庫緩存之前,你必須用這個指令來建立緩存表:

python manage.py createcachetable
           

1.5 Memcache緩存(python-memcached子產品)

Memcached有一個非常好的特點就是可以讓幾個服務的緩存共享。 這就意味着你可以在多台機器上運作Memcached服務,這些程式将會把這幾個機器當做 同一個 緩存,進而不需要複制每個緩存的值在每個機器上。為了使用這個特性,把所有的服務位址放在LOCATION裡面,用分号隔開或者當做一個list。

# 此緩存使用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',
            ]
        }
    }
           

1.6 Memcache緩存(pylibmc子產品)

# 此緩存使用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',
            ]
        }
    }
           

2. 緩存應用

緩存應用分為三種模式:

  • 站點級緩存
  • 單個視圖緩存
  • 模闆片段緩存

2.1 站點級緩存

一旦高速緩存設定,最簡單的方法是使用緩存緩存整個網站。

使用中間件,經過一系列的認證等操作,如果内容在緩存中存在,則使用FetchFromCacheMiddleware擷取内容并傳回給使用者,當傳回給使用者之前,判斷緩存中是否已經存在,如果不存在則UpdateCacheMiddleware會将緩存儲存至緩存,進而實作全站緩存

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


CACHE_MIDDLEWARE_ALIAS = ""      # 用于存儲的緩存的别名
CACHE_MIDDLEWARE_SECONDS = ""    # 每個page需要被緩存多少秒。這個優先級大于CACHES中的TIMEOUT參數。
CACHE_MIDDLEWARE_KEY_PREFIX = ""  # 如果緩存被使用相同Django安裝的多個網站所共享,那麼把這個值設成目前網站名,或其他能代表這個Django執行個體的唯一字元串,以避免key發生沖突。 如果你不在意的話可以設成空字元串。
    
           
注意: 'Update'中間件,必須放在清單的開始位置,而Fectch中間件,必須放在最後。

2.2 單個視圖緩存

#方式一:
from django.views.decorators.cache import cache_page

cache_page(60 * 15)    # 60秒*15,也就是緩存15分鐘
def my_view(request):
    pass

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

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]
           
注意:cache_page接受一個參數:timeout,秒為機關。在前例中,“my_view()”視圖的結果将被緩存 15 分鐘 (注意為了提高可讀性我們寫了 60 * 15 . 60 * 15 等于 900 –也就是說15分鐘等于60秒乘15.)

2.3 模闆片段緩存

在模版檔案中加入

# a. 引入TemplateTag

     {% load cache %}

# b. 使用緩存

     {% cache 5000 緩存key %}
         緩存内容
     {% endcache %}
           
注意:5000是指緩存5000秒,緩存的key可以是自定義的字元串。

二、序列化

關于Django中的序列化主要應用在将資料庫中檢索的資料傳回給用戶端使用者,特别的Ajax請求一般傳回的為Json格式。

1、serializers

from django.core import serializers
 
ret = models.BookType.objects.all()
 
data = serializers.serialize("json", ret)
           

2、json.dumps

import json
 
#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption')
 
ret=list(ret)
 
result = json.dumps(ret)
           

由于json.dumps時無法處理datetime日期,是以可以通過自定義處理器來做擴充,如:

import json 
from datetime import date 
from datetime import datetime 
   
class JsonCustomEncoder(json.JSONEncoder): 
    
    def default(self, field): 
     
        if isinstance(field, datetime): 
            return o.strftime('%Y-%m-%d %H:%M:%S') 
        elif isinstance(field, date): 
            return o.strftime('%Y-%m-%d') 
        else: 
            return json.JSONEncoder.default(self, field) 
   
   
# ds = json.dumps(d, cls=JsonCustomEncoder) 
           

三、信号

Django中提供了“信号排程”,用于在架構執行操作時解耦。通俗來講,就是一些動作發生的時候,信号允許特定的發送者去提醒一些接受者。

1. 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内置的信号,僅需注冊指定信号,當程式執行相應操作時,自動觸發注冊函數:

需要将觸發信号的代碼放在項目下同項目名稱的目錄下的init.py中,例如django項目名稱為myblog,則需要将下列代碼寫至myblog/myblog/init.py中。

需求:當對某個資料庫做寫入操作時,就觸發某個函數的執行。

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 signal(sender,**kwargs):
    print('Django信号測試')
    print('sender: ',sender)
    print('kwargs: ',kwargs)

# 調用信号的connect方法,将自定義的函數當作參數傳遞進去
post_save.connect(signal)      # 當對資料庫做儲存操作時,就會觸發上述signal函數的執行
           
注意:自定義的函數傳入一個位置參數sender,它是觸發此函數執行的某個子產品;kwargs内容請看下面列印結果;
# 列印結果如下:
# Django信号測試
# sender:  <class 'blog.models.Blog'>
# kwargs:  {'update_fields': None, 'created': True, 'instance': <Blog: 我的python>, 'signal': <django.db.models.signals.ModelSignal object at 0x0000000002E00FD0>, 'using': 'default', 'raw': False}