Django-redis 实现Redis结果自动解码的一种方式
Django-redis使用时遇到的坑
Django-redis
是一个为Django提供redis操作一个python库,它可以提供redis的cache和原生的redis接口,在Django使用redis时,加入这个库会非常方便,不过今天在用这个库的时候出现了一些问题,这些问题都比较麻烦,通过分析源码之后得到以下一些结论。
参数不起作用
Django-redis可以选择redis-py作为redis接口的实现类,在使用的时候碰到这样一个问题:一般我们都是用redis来缓存一些东西,而redis自身支持的数据类型有限,一般都是字符串,而这些字符串的编码可能并不确定,实际在Redis中一般是保存一个bytes的数组,而在python中字符一直都是UTF-8的数据,这二者了不一致就造成的一些问题。在一般的redis
client中为了避免类似的问题,Redis的类中支持一个decode_responses
的参数,这个参数可以实现对redis返回结果的一个解码处理,在快速开发中显得十分重要,而在django-redis
这个扩展中,没有实现自动解码的功能,这个主要是因为django-redis
采用的是redis connection pool
的原因,通过翻阅源代码发现,py-redis
只在一般的client中有自动解码的选项,而如果client采用connection
pool的方式实现的话,这些多余的选项是不被支持的,究其原因是因为connection pool中的各种连接之间是有差异的,编码上可能也会有一定的差异。
曲线解决方法
既然自动解码的方式在django-redis
和py-redis
上行不通,那么我们可以通过一种变通的方式实现一个自定义的带有解码的Redis Client, 实现的基本思路其实比较简单,实际就是在调用redis相关命令后对结果进行一个解码的处理就可以了,python
中灵活的魔法方法可以非常方便的实现这个需求,在django-redis
中,一个原生的redis是一个类的实例,可以通过以下的方式实现这个类的实例化:
from django_redis import get_redis_connection
conn = get_redis_connection('default')
我们需要做的是定义一个类来取代这个类,而底层的调用还是会去调用这个类的方法,不过是将其输出做一个简单的解码处理就可以了,其实现方式如下:
from django_redis import get_redis_connection
def parse_redis(obj):
if isinstance(obj, bytes):
return obj.decode('utf-8')
elif isinstance(obj, set):
return set(x.decode('utf-8') for x in obj)
elif isinstance(obj, list):
return [x.decode('utf-8') for x in obj]
else:
return obj
def tocontainer(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return parse_redis(result)
return wrapper
class Redis(object):
def __init__(self, conf='default'):
self.conn = get_redis_connection(conf)
def __getattr__(self, func):
return tocontainer(getattr(self.conn, func))
redis = Redis('default')
在上述代码中parse_redis
是一个对redis返回结果做解码处理的一个函数,tocontainer
是一个函数方法,它相当于一个装饰函数,调用parse_redis
对结果进行处理。Redis
是取代原生``redis
client的一个类,它之所以可以取代原生的方法,主要利益于一个
getattr的魔法函数,这个函数是读取类成员变量的时候会自动调用,而类的方法实际也是类下面的一种特殊的函数变量,所以可以在
getattr中捕获对类方法的调用,然后将类方法的调用改成对底层
conn下面方法的调用,对
conn这个实例,我们可以通过
getattr``方法实现对其成员变量的查找,找到相应的方法之后,对找到的方法进行包装,成为一个新的方法返回,这样就可以实现对结果的处理,就相当于用一个在原有方法基础上实现一个新的方法,并直接取代原生的方法。
最后更新于 2017-11-06 07:38:51 并被添加「」标签,已有 5121 位童鞋阅读过。
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
大哥牛逼