Django中模型的使用
前面的两篇博客介绍了Django中ORM的基础知识及其使用,我们配合使用的数据库是关系型数据库MySQL,这篇博客我们介绍如何在Django中使用非关系型数据库Redis。
Redis是一个基于内存的非关系型数据库。它通过key:value的形式存储。有着多种数据结构,如字符串,列表,集合等。通过redis,我们可以进行数据缓存,防止底层数据库频繁io,提升性能。
因为MySQL数据库中的数据存储于本地磁盘,在MySQL中进行查询,需要在磁盘进行数据的IO操作,当访问量较大的时候,频繁的磁盘IO会降低系统的性能;而Redis是基于内存的数据库,数据存储在内存当中,查询性能较好,如果把频繁读取的数据存在内存当中,可以极大提升系统的性能。
下面介绍如何在Django中使用Redis数据库。
这篇博客主要实现的功能是:编写装饰器函数,对查询函数进行优化,如果内存中存在查询的数据,直接从内存中进行读取;如果内存中不存在查询的数据,则再去本地数据库中进行查询,然后将该数据添加到内存当中,下次查询就可以从内存中获取。
准备工作
1. 电脑上完成Redis安装,并启动Redis服务
2. 安装Python依赖库,django-redis
3. Django项目中进行相关的配置(settings.py)
使用过程
(1)Django中调用Redis
基于我们安装的Python依赖库django_redis可以进行Redis数据库的调用,使用方式如下:
from django_redis import get_redis_connection
# default为我们在配置文件中的配置信息
conn = get_redis_connection('default')
conn.set('key', 'value', 'valid_time')
result = conn.get('key')
(2)在模型类User中实现普通的查询函数(在本地数据库MySQL中进行查询)
class User(models.Model):
# 设置姓名为unique;不允许有相同名称的用户,也不允许姓名为空
name = models.CharField(max_length=50, unique=True, null=False)
# 用户的年龄不会出现特别大的数值,因此设置为SmallInteger
age = models.SmallIntegerField(default=0)
# 电话信息可以允许为空;设置为普通索引,将来可以根据电话进行查询
phone = models.IntegerField(null=True, db_index=True)
email = models.EmailField(null=True, default='')
info = models.TextField(null=True)
# 创建时间:只在创建时候记录,之后不会进行修改;会自动添加到数据库,不必传入
create_time = models.DateTimeField(auto_now_add=True)
# 更新时间:每次修改都会记录修改的时间;会自动添加到数据库,不必传入
update_time = models.DateTimeField(auto_now=True)
class Meta:
# 普通联合索引
index_together = ['name','age']
# 唯一联合索引
unique_together = ['name','phone']
# classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,
# 但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。
@classmethod
def get(cls, id):
re = cls.objects.get(id=id)
return {
'id':re.id,
'name':re.name,
'age':re.age,
'phone':re.phone,
'email':re.email,
'info':re.info,
'create_time':str(re.create_time),
'update_time':str(re.update_time)
}
(3)装饰器函数的实现
from django_redis import get_redis_connection
from functools import wraps
import json
_conn = get_redis_connection('default')
def cache(func):
@wraps(func)
# 对于用于修饰类中函数的装饰器,第一个参数应该是obj,对应类中函数的self或者cls
# *args表示函数实际传入的参数
def read_from_redis(obj, *args):
key = func.__name__ + "_" + str(args[0])
# 首先从内存中获取数据
result = _conn.get(key)
if result:
print('成功从Redis中读取到数据!!!')
return json.loads(result)
print('Redis中没有相关数据。。。。')
result = func(obj, *args)
add = _conn.set(key, json.dumps(result))
if add:
print('成功将数据存储到Redis中!')
return '装饰器执行完毕'
return read_from_redis
(4)调用过程如下:
因为User类中的get函数使用@classmethod修饰符进行修饰,所以我们在调用User中的get方法的时候,不需要实例化对象:
第一次调用get函数的时候,因为内存中没有数据,所以会显示上面的信息,此时id=1的数据被添加到内存当中。
这时,我们在Redis数据库中进行查看:
此时,内存中有了id=1的数据,当我们再次调用get函数,获取id=1的用户信息时,会直接从内存中读取,不再进行本地MySQL查找的步骤,如下所示:
参考资料
1、https://coding.imooc.com/class/393.html
2、https://www.runoob.com/python/python-func-classmethod.html