封装了ORM框架
Project description
使用方法:
pip install kxy-framework
from kxy.framework.context import *
数据权限过滤
框架会在 BaseDal 的统一查询、更新、删除入口自动追加数据权限过滤条件。使用方一般只需要完成两件事:
- 在模型类上声明哪些字段参与数据权限。
- 在请求入口写入当前登录用户的数据权限上下文。
1. 模型声明
推荐使用 DataPermission 一次性声明租户、部门、本人字段:
from kxy.framework.filter import DataPermission
@DataPermission(
tenant_field="TenantId",
dept_field="DepId",
user_field="CreateUser",
)
class Customer(BaseEntity, Modal):
__tablename__ = "customer"
也兼容旧写法:
from kxy.framework.filter import FilterTenant, FilterDepartment, FilterUser
@FilterTenant("TenantId")
@FilterDepartment("DepId")
@FilterUser("CreateUser")
class Customer(BaseEntity, Modal):
__tablename__ = "customer"
2. 请求入口设置上下文
基础库不负责查询角色、组织和部门树。业务系统应在登录后或请求中间件中计算好当前用户最终可见范围,再写入上下文:
from kxy.framework.context import user_id, current_tenant_id, dep_id
from kxy.framework.data_permission import (
DataScope,
set_data_permission_context,
)
user_id.set(login_user["id"])
current_tenant_id.set(login_user["tenant_id"])
dep_id.set(login_user["dept_id"])
# 示例:可看本部门及子部门,同时可看本人创建的数据
set_data_permission_context(
scope=DataScope.DEPT_AND_CHILD,
dept_ids=login_user["visible_dept_ids"],
child_dept_ids=login_user["child_dept_ids"],
allow_self=True,
)
3. 业务查询无需手动拼权限条件
items, total = await customer_dal.paginate_query(
filters,
Customer.CreateDate.desc(),
page_index,
page_size,
)
如果模型声明了 tenant_field="TenantId"、dept_field="DepId"、user_field="CreateUser",最终效果类似:
WHERE 业务条件
AND TenantId = 当前租户
AND (DepId IN (可见部门) OR CreateUser = 当前用户)
4. 数据范围说明
DataScope.ALL # 全部数据,不追加部门/本人过滤
DataScope.DEPT_CUSTOM # 指定部门,使用 data_scope_dept_ids
DataScope.DEPT_ONLY # 当前部门,使用 dep_id
DataScope.DEPT_AND_CHILD # 当前部门及子部门,使用 dep_id + child_dep_ids + data_scope_dept_ids
DataScope.SELF # 仅本人,使用 user_field == user_id
多角色并集建议由业务系统先计算成最终结果,再写入 data_scope_dept_ids、self_data_permission 等上下文。
如果部门配置为 *,表示全部部门,框架不会追加部门/本人数据权限条件,只保留租户等其它过滤:
set_data_permission_context(
scope=DataScope.DEPT_CUSTOM,
dept_ids=["*"],
)
5. 临时忽略数据权限
忽略全部过滤:
from kxy.framework.data_permission import data_permission_ignore
async with data_permission_ignore():
data = await customer_dal.QueryWhere([Customer.Id == id])
只忽略部门/本人过滤,保留租户过滤:
async with data_permission_ignore("dept", "self"):
data = await customer_dal.QueryWhere([Customer.Id == id])
也可以用于方法装饰器:
from kxy.framework.data_permission import ignore_data_permission
@ignore_data_permission("dept", "self")
async def check_unique(self, name):
return await self.QueryOne([Customer.Name == name])
6. 注意事项
BaseDal.Get、QueryWhere、QueryOne、QueryCount、paginate_query、UpdateFields、DeleteWhere等会自动追加过滤。ExecSql(sql: str)是裸 SQL,框架无法安全改写,不会自动注入数据权限;使用时需要业务方自行拼接权限条件。- 未设置
data_scope时,框架保持旧版行为:FilterDepartment按dep_id等值过滤,FilterUser按user_id等值过滤。
日志
from kxy.framework.slogger import create_logger
logger,handler = create_logger(logging.DEBUG,'appName','production',filename='log/app',file_type='log',backupCount=5,maxBytes=10485760,mutiple_process=False)
# mutiple_process 是否多进程,多进程需要生成不同的文件
logger.info('hello world',extra={"logCategory":'http'})
日志进阶用法,设置traceId:
from kxy.framework.slogger import user_id,user_info,new_trace
req_trace_id = request.headers.get("X-Trace-ID") or str(uuid4())
new_trace(req_trace_id)
user_id.set('login user id')
# user_info用于存储用户自定义的信息,方便在其他地方取用
user_info.set({'name':'login user name','email':'login user email'})
日志自定义打印格式:
class JsonFormatter(logging.Formatter):
def format(self, record):
# 构建日志记录的字典
log_record = {
"appName":appName,
"serverAddr":os.environ.get('IP',localIp),
"cluster": env,
"levelname": record.levelname,
"filename": record.filename,
"lineno": record.lineno,
"traceId": record.trace_id,
"sessionId": record.session_id,
"userId":record.userid,
"seqId": record.seq,
"message": record.getMessage(),
"CreateTime": self.formatTime(record, self.datefmt),
"createdOn": int(time.time() * 1000) # 添加 Unix 时间戳
}
# 将字典转换为 JSON 字符串
return json.dumps(log_record, ensure_ascii=False)
from simple_util.slogger import create_logger
logger,handler = create_logger(logging.DEBUG,'appName','production',filname='log/app',file_type='log',backupCount=5,maxBytes=10485760)
handler.setFormatter(JsonFormatter())
logger.info('hello world')
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kxy_framework-1.4.16.tar.gz.
File metadata
- Download URL: kxy_framework-1.4.16.tar.gz
- Upload date:
- Size: 42.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c555cd1964b7eacb5565056f9bcf562db708dcaa6d049a49a47dfe6c1d7936fa
|
|
| MD5 |
9d33a25c9fbc9187f1e6b6762720a17e
|
|
| BLAKE2b-256 |
624d518d9ac2d917b3b6073f4c727808b60b72ae5ded1a1c6200f64e86cd50f1
|
File details
Details for the file kxy_framework-1.4.16-py3-none-any.whl.
File metadata
- Download URL: kxy_framework-1.4.16-py3-none-any.whl
- Upload date:
- Size: 73.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
720fea7d68b2a552e7adb458421dc4e117a561f804cf3bdd08cfb658bf3091a0
|
|
| MD5 |
76761f4167d8596db202da0d44a6b4dc
|
|
| BLAKE2b-256 |
eb02a51fdf5a2ce40c624b5e42a4340a7cf9c2914b9bf2b198818592e4b5bd5e
|