[Django]Redisの使用[オリジナル]

0.リファレンス

django-redisの中国語ドキュメント



DjangoでRedisを使用する方法は2つあります。

  • カスタムモード
  • サードパーティのコンポーネントを使用する[推奨]

1.カスタムモード

このようにして、Djangoを使用できるだけでなく、他のフレームワークやネイティブPythonも使用できます。


A.依存関係をインストールします

pip install redis

B.Redis構成

モジュールにカプセル化され、グローバルに使用できます

import redis

# 抽取封装成模块,全局使用(单例模式,redis_pool.py)
POOL = redis.ConnectionPool(host='xx.xx.xx.xx', port=6379, password='xxx', max_connections=1000)

c。使用

# 引用全局连接池
from redis_pool import POOL

conn = redis.Redis(connection_pool=POOL)
conn.set(key, value)

2.サードパーティコンポーネントの使用

Djangoの場合は、この方法を使用することをお勧めします


A.依存関係をインストールします

pip install django-redis

B. Redis構成(settings.py)

CACHES = {
    
    
    "default": {
    
    
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
    
    
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {
    
    "max_connections": 100, 'decode_responses': True},
            # "PASSWORD": "密码",
        },
        # 前缀
        "KEY_PREFIX": "test"
    }
}

注:max_connectionsは接続プールです。不要な場合は削除できます
。注:プレフィックスは個人のニーズによって異なります。
-8、この設定を追加すると、読み取り時にデコードする必要がありません。ただし、decode_responsesがTrueに設定されている場合、以下の2番目の方法を使用してキャッシュを読み取ると、エラーが報告されます。
次に例を示します。

>>> from django_redis import get_redis_connection
>>> conn = get_redis_connection()
>>> conn.set('redis_test3', 22)
True
>>> conn.get('redis_test3')
b'22'

注:複数のRedisがある場合は、CACHEに新しいRedisを追加できます。これは、デフォルトとは異なります。


c。使用

2つの方法があります:

  • get_redis_connection
  • キャッシュ

最初の方法:get_redis_connection
はこの方法を推奨しています

from django_redis import get_redis_connection
 
# 这里可以传使用哪个redis,不传默认是default
redis = get_redis_connection()
redis.get(key)
redis.set(key, value)

注:decode_responsesがTrueに設定されていない場合、get_redis_connectionを使用して読み取られるデータはバイトであり、utf-8にデコードする必要があります。この設定を追加する場合、自分でデコードする必要はありません。
例:

>>> from django_redis import get_redis_connection
>>> conn = get_redis_connection()
>>> conn.set('redis_test3', 22)
True
>>> conn.get('redis_test3')
b'22'

注:この方法を使用すると、キャッシュ内のプレフィックスは有効になりません。つまり、redisに設定されている場合、キーはそのままで、プレフィックスは自動的に追加されません。


2番目の方法:キャッシュ

from django.core.cache import cache
 
cache.get(key)
cache.set(key, value)

注:キャッシュ内のdecode_responsesがTrueに設定されている場合、読み取りはエラーを報告します

>>> cache.get('redis_test3')
Traceback (most recent call last):
  File "c:\users\jiand\appdata\local\programs\python\python37\Lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<console>", line 1, in <module>
  File "D:\Python\Envs\Django2Demo\lib\site-packages\django_redis\cache.py", line 87, in get
    value = self._get(key, default, version, client)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\django_redis\cache.py", line 27, in _decorator
    return method(self, *args, **kwargs)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\django_redis\cache.py", line 94, in _get
    return self.client.get(key, default=default, version=version, client=client)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\django_redis\client\default.py", line 220, in get
    value = client.get(key)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\redis\client.py", line 1579, in get
    return self.execute_command('GET', name)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\redis\client.py", line 878, in execute_command
    return self.parse_response(conn, command_name, **options)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\redis\client.py", line 892, in parse_response
    response = connection.read_response()
  File "D:\Python\Envs\Django2Demo\lib\site-packages\redis\connection.py", line 734, in read_response
    response = self._parser.read_response()
  File "D:\Python\Envs\Django2Demo\lib\site-packages\redis\connection.py", line 358, in read_response
    response = self.encoder.decode(response)
  File "D:\Python\Envs\Django2Demo\lib\site-packages\redis\connection.py", line 129, in decode
    value = value.decode(self.encoding, self.encoding_errors)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte

概要:
これら2つの方法のいずれかを選択できます。1つを使用することをお勧めします。get_redis_connectionを使用し、キャッシュのdecode_responsesをTrueに設定することをお勧めします。
両方の方法を使用する必要がある場合は、decode_responsesの構成をから削除してください。キャッシュしてから、get_redis_connectionを使用してバイトを文字列に変換するときに読み取ります。

redis_value = self.conn.get(lock_name)

# 注意:如果是get_redis_connection的话,从redis里面读取的是bytes字符的
redis_value = redis_value.decode('utf-8') if isinstance(redis_value, bytes) else redis_value

サンプルコード

from django_redis import get_redis_connection

def get_private_ips(self, subnet_id, is_ignore_cache=False):
    """
    查询私有IP列表
    使用Redis缓存,保存1小时
    :param subnet_id:
    :param is_ignore_cache: 是否忽略缓存 默认是否
    :return:
    """
    key = 'HW_private_ips_area_%s_subnetId_%s' % (self.area, subnet_id)
    cache = get_redis_connection()

    # 保存1小时
    expired_time = 60 * 60 * 1
    res = cache.get(key, None)

    if not res or is_ignore_cache:
        sig = self.sig
        uri = "/v1/{0}/subnets/{1}/privateips".format(sig.ProjectId, subnet_id)
        res = self._hw_request(uri)

        if res and not res.get('code') and res.get('privateips'):
            cache.set(key, res, expired_time)

    return res

単純なRedisロックの実装:

from django_redis import get_redis_connection


class LockService:
    def __init__(self, conn=None):
        """
        如果不传连接池的话,默认读取配置的Redis作为连接池
        :param conn:
        """
        self.conn = conn if conn else get_redis_connection()

    def acquire_lock(self, lock_name, value, expire_time=60):
        """
        加锁
        如果不存在lock_name,则创建,并且设置过期时间,避免死锁
        如果存在lock_name,则刷新过期时间

        插入成功:返回True
        已存在:返回False并且刷新过期时间
        :param lock_name:
        :param value:
        :param expire_time:
        :return:
        """
        if self.conn.setnx(lock_name, value):
            # 注意:Todo 这里可能会有问题,如果程序在写入redis之后但未设置有效期之前突然崩溃,则无法设置过期时间,将发生死锁
            self.conn.expire(lock_name, expire_time)
            return True
        elif self.conn.ttl(lock_name):
            self.conn.expire(lock_name, expire_time)
        return False

    def release_lock(self, lock_name, value):
        """
        释放锁
        注意:只有value值一致才会删除,避免在并发下删除了其他进程/线程设置的锁
        :param lock_name:
        :param value:
        :return:
        """
        redis_value = self.conn.get(lock_name)

        # 注意:如果是get_redis_connection的话,从redis里面读取的是bytes字符的
        redis_value = redis_value.decode('utf-8') if isinstance(redis_value, bytes) else redis_value
        if str(redis_value) == str(value):
            self.conn.delete(lock_name)

おすすめ

転載: blog.csdn.net/jiandanokok/article/details/109426427