Files
FastapiAdmin/backend/app/core/cache_util.py
T
zhangtao afdd805e11 refactor: 重构查询参数实现,替换旧的__init__初始化方式为dataclass+post_init
feat: 新增岗位编码字段与校验
fix: 修复批量删除提示、请求缓存、任务状态等逻辑
perf: 优化表格列展示,移除冗余ID列
build: 降级fastapi版本至0.115.2,更新依赖锁文件
docs: 补充部分代码注释与说明
2026-06-22 00:27:23 +08:00

66 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""轻量 Redis 缓存工具(替代 fastapi-cache2,兼容 redis-py"""
import hashlib
import json
from collections.abc import Callable
from functools import wraps
from typing import Any
from redis.asyncio.client import Redis
from starlette.responses import Response
_ENABLE: bool = True
_EXPIRE: int = 300
_PREFIX: str = "fastapi-admin-cache"
_REDIS: Redis | None = None
async def init(redis: Redis, prefix: str = "fastapi-admin-cache", expire: int = 300, enable: bool = True) -> None:
global _REDIS, _PREFIX, _EXPIRE, _ENABLE
_REDIS = redis
_PREFIX = prefix
_EXPIRE = expire
_ENABLE = enable
def _build_key(namespace: str, func: Callable, *args: Any, **kwargs: Any) -> str:
raw = f"{func.__module__}:{func.__qualname__}:{args}:{kwargs}"
return f"{_PREFIX}:{namespace}:{hashlib.md5(raw.encode()).hexdigest()}"
def cache(expire: int | None = None, namespace: str = "default"):
def decorator(func: Callable):
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> Any:
if not _ENABLE or _REDIS is None:
return await func(*args, **kwargs)
key = _build_key(namespace, func, *args, **kwargs)
cached = await _REDIS.get(key)
if cached:
data = json.loads(cached)
return Response(
content=json.dumps(data, ensure_ascii=False),
media_type="application/json; charset=utf-8",
status_code=200,
)
result = await func(*args, **kwargs)
# 提取 Response 对象的 body 进行缓存
if isinstance(result, Response):
body = result.body
else:
body = json.dumps(result).encode()
await _REDIS.set(key, body, ex=expire or _EXPIRE)
return result
return wrapper
return decorator
async def clear(namespace: str | None = None) -> None:
if _REDIS is None:
return
pattern = f"{_PREFIX}:{namespace}:*" if namespace else f"{_PREFIX}:*"
keys = [key async for key in _REDIS.scan_iter(match=pattern)]
if keys:
await _REDIS.delete(*keys)