【FastAPI 学习 十】使用Redis
在FastAPI中 使用Redis
FastAPI官网关于异步的解释描述 https://fastapi.tiangolo.com/async/
建议要使用FastAPI的人,都看看作者关于异步的描述
思路
把redis_cli
对象挂载到FastAPI
app 对象上面,然后在视图函数中使用默认的回调参数request
对象获取
2021年1月30号更新 直接使用全局redis客户端对象,实现方式在最下面。
参考链接
https://github.com/tiangolo/fastapi/issues/1694
https://github.com/tiangolo/fastapi/issues/1742
https://github.com/leonh/redis-streams-fastapi-chat/blob/master/chat.py
测试代码
安装aioredis
pip intsall aioredis
完整代码,新建一个test_aioredis.py
文件
from aioredis import create_redis_pool, Redis
from fastapi import FastAPI, Request, Query
app = FastAPI()
async def get_redis_pool() -> Redis:
redis = await create_redis_pool(f"redis://:root12345@172.16.137.129:6379/0?encoding=utf-8")
return redis
@app.on_event('startup')
async def startup_event():
"""
获取链接
:return:
"""
app.state.redis = await get_redis_pool()
@app.on_event('shutdown')
async def shutdown_event():
"""
关闭
:return:
"""
app.state.redis.close()
await app.state.redis.wait_closed()
@app.get("/test", summary="测试redis")
async def test_redis(request: Request, num: int=Query(123, title="参数num")):
# 等待redis写入 await异步变同步 如果不关心结果可以不用await,但是这里下一步要取值,必须得先等存完值 后再取值
await request.app.state.redis.set("aa", num)
# 等待 redis读取
v = await request.app.state.redis.get("aa")
print(v, type(v))
return {"msg": v}
if __name__ == '__main__':
import uvicorn
uvicorn.run(app='test_aioredis:app', host="127.0.0.1", port=8080, reload=True, debug=True)
上面只是一个文件, 如何在项目中组织了? 很多博客,都是单文件演示,不够友好。
FastAPI项目中组织
仿照 flask 注册挂载redis
def create_app():
"""
生成FatAPI对象
:return:
"""
app = FastAPI()
# 其余的一些全局配置可以写在这里 多了可以考虑拆分到其他文件夹
# 跨域设置
# 注册路由
# 注册捕获全局异常
# 请求拦截
# 挂载redis
register_redis(app)
return app
def register_redis(app: FastAPI) -> None:
"""
把redis挂载到app对象上面
:param app:
:return:
"""
@app.on_event('startup')
async def startup_event():
"""
获取链接
:return:
"""
app.state.redis = await create_redis_pool(settings.REDIS_URL)
@app.on_event('shutdown')
async def shutdown_event():
"""
关闭
:return:
"""
app.state.redis.close()
await app.state.redis.wait_closed()
使用
这个就和上面例子一样,直接使用。
@app.get("/test", summary="测试redis")
async def test_redis(request: Request, num: int=Query(123, title="参数num")):
# 等待redis写入 await异步变同步 如果不关心结果可以不用await,但是这里下一步要取值,必须得先等存完值 后再取值
await request.app.state.redis.set("aa", num)
# 等待 redis读取
v = await request.app.state.redis.get("aa")
print(v, type(v))
return {"msg": v}
更改初始化位置
2021年1月30号更新
之前是吧 redis 对象放在了 请求对象上面,有时候就感觉特别不合理,于是就又找了个方式 直接全局引用。
Python不像Go可以通过指针直接修改原来的对象,但是可以通过class 实例化对象可以直接修改内部属性的特性
再通过魔法方法,赋予实例化对象 具有内部属性_redis_client的方法和属性,就达到了上述的目的了。
具体代码如下:
import sys
import redis
from common.logger import logger
from core.config import settings
class RedisCli(object):
def __init__(self, *, host: str, port: int, password: str, db: int, socket_timeout: int = 5):
# redis对象 在 @app.on_event("startup") 中连接创建
self._redis_client = None
self.host = host
self.port = port
self.password = password
self.db = db
self.socket_timeout = socket_timeout
def init_redis_connect(self) -> None:
"""
初始化连接
:return:
"""
try:
self._redis_client = redis.Redis(
host=self.host,
port=self.port,
password=self.password,
db=self.db,
socket_timeout=5,
decode_responses=True # 解码
)
if not self._redis_client.ping():
logger.info("连接redis超时")
sys.exit()
except (redis.AuthenticationError, Exception) as e:
logger.info(f"连接redis异常 {e}")
sys.exit()
# 使实例化后的对象 赋予redis对象的的方法和属性
def __getattr__(self, name):
return getattr(self._redis_client, name)
def __getitem__(self, name):
return self._redis_client[name]
def __setitem__(self, name, value):
self._redis_client[name] = value
def __delitem__(self, name):
del self._redis_client[name]
# 创建redis连接对象 但是这种方式使用方法时没有提示
redis_client = RedisCli(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
password=settings.REDIS_PASSWORD,
db=settings.REDIS_DB
)
# 只允许导出 redis_client 实例化对象
__all__ = ["redis_client"]
然后在 redis对象 在 @app.on_event("startup")
中使用init_redis_connect
方法创建连接即可,然后其他地方可直接引用这个redis对象操作,但是不方便的由于Python没有强制指定类型这一点,所以使用时没有方法提示。
总结
最后推荐每个使用FastAPI的开发者都看下这个
FastAPI官网关于异步的解释描述 https://fastapi.tiangolo.com/async/
话说这个async
await
语法糖和js ES6特别像
具体完整GitHub代码
见个人网站https://www.charmcode.cn/article/2020-07-29_fastapi_redis