Archery SQLQuery 接口 DRF 统一迁移实战指南:接口清单、兼容别名与验证流程

发布时间:2026/10/4 1:56:57
Archery SQLQuery 接口 DRF 统一迁移实战指南:接口清单、兼容别名与验证流程 后端数据库【免费下载链接】ArcherySQL 审核查询平台项目地址https://gitcode.com/gh_mirrors/ar/Archery点击查看免费下载导读本文围绕 Archery 中002-migrate-sqlquery-api特性的 Quickstart 文档完整梳理 SQL 查询页面 6 项后端能力向 Django REST FrameworkDRF统一接口迁移后的规范端点canonical endpoint、旧 URL 兼容别名legacy alias、请求/响应示例、手工验证流程与聚焦测试命令。读完本文你将掌握在 sql_api 模块中新增的/api/v1/sqlquery/*接口的调用方式、与旧页面入口/query/、/instance/instance_resource/等的对应关系以及如何用 pytest 回归验证迁移后权限、脱敏、超时终止与历史收藏行为的一致性。1. 迁移背景与接口范围本特性源自用户需求希望将 sqlquery查询 SQL 涉及到的所有接口改成 django rest framework 实现以充分利用其授权配置见 spec.md。迁移采用后端优先兼容策略在sql_api新增面向 SQLQuery 场景的 DRF 视图与序列化器将 sql/query.py、sql/instance.py、sql/resource_group.py 中的业务逻辑抽取到可复用的服务层同时保留旧 URL 兼容别名或直接重绑到 DRF 视图尽量不改前端调用代码。迁移覆盖页面上的6 个用户能力对应 FR-001 至 FR-012见 spec.md能力说明优先级获取用户可访问实例页面实例下拉框数据源P3获取实例下的 database数据库选择器数据源P3获取实例与 database 下的 table表选择器数据源P3执行查询含权限校验、行数限制、超时、脱敏、审计P1MVP读取历史查询记录分页、筛选、搜索、按角色限可见范围P2收藏/取消收藏 SQL含别名维护、写权限校验P2从源码结构看sql_api/api_sqlquery.py 共实现了 6 个 DRF 视图类与上述能力一一对应外加一个describetable表结构接口。2. 规范端点Canonical EndpointsQuickstart 文档给出的 5 个规范端点为另加表结构接口见 sql_api/urls.py方法路径用途GET/api/v1/sqlquery/instances/当前用户可访问的实例列表GET/api/v1/sqlquery/resources/某实例下的 database/table 等资源POST/api/v1/sqlquery/execute/执行一条 SQL 查询GET/api/v1/sqlquery/logs/查询历史记录bootstrap-table 结构POST/api/v1/sqlquery/favorites/收藏/取消收藏一条查询记录POST/api/v1/sqlquery/describetable/查看表结构这些路由在 sql_api/urls.py 中注册为path(v1/sqlquery/instances/, api_sqlquery.SQLQueryInstancesView.as_view()), path(v1/sqlquery/resources/, api_sqlquery.SQLQueryResourcesView.as_view()), path(v1/sqlquery/describetable/, api_sqlquery.SQLQueryDescribeTableView.as_view()), path(v1/sqlquery/execute/, api_sqlquery.SQLQueryExecuteView.as_view()), path(v1/sqlquery/logs/, api_sqlquery.SQLQueryLogsView.as_view()), path(v1/sqlquery/favorites/, api_sqlquery.SQLQueryFavoritesView.as_view()),规范的 OpenAPI 契约定义在 contracts/sqlquery-api.openapi.yaml涵盖每个端点的参数、请求体与响应 Schema可直接用于 drf-spectacular 生成 Swagger/Redoc 文档。2.1 授权模型迁移后的页面场景接口显式使用permissions.IsAuthenticated endpoint-specific 权限校验而不是沿用REST_FRAMEWORK默认的IsInUserWhitelist决策详见 research.md Decision 2。原因在于默认白名单面向开放 API直接继承会导致 SQL 查询页面的大部分 AJAX 请求被拒绝。从 sql_api/api_sqlquery.py 源码可以看到每个视图的权限口径SQLQueryInstancesView/SQLQueryResourcesView/SQLQueryDescribeTableView仅要求IsAuthenticated实例与资源范围由服务层通过user_instances()收敛SQLQueryExecuteView要求超级用户或拥有sql.query_submit权限否则返回{status: 1, msg: 无执行查询权限, data: {}}SQLQueryLogsView要求超级用户或sql.menu_sqlquery/sql.audit_user权限无权时返回{total: 0, rows: []}SQLQueryFavoritesView要求超级用户或sql.menu_sqlquery权限无权时返回{status: 1, msg: 无收藏操作权限}。角色可见性规则普通用户只能看自己的历史、审计角色与超级用户范围更广在 sql/services/querylog_service.py 中通过filter_dict[username] user.username实现。3. 旧页面入口的兼容别名Legacy Aliases为了保证现有页面不改前端即可继续工作旧 URL 被保留并与规范端点一一对应旧 URL页面当前调用规范端点对应能力GET /group/user_all_instances/GET /api/v1/sqlquery/instances/实例列表GET /instance/instance_resource/GET /api/v1/sqlquery/resources/实例资源POST /query/POST /api/v1/sqlquery/execute/执行查询GET /query/querylog/GET /api/v1/sqlquery/logs/查询历史POST /query/favorite/POST /api/v1/sqlquery/favorites/收藏操作该映射同时记录在 contracts/sqlquery-api.openapi.yaml 的描述区与 plan.md 的 API contracts 章节。任务清单 tasks.md 中的 T008、T032 要求在 sql/urls.py 与sql/resource_group.py、sql/instance.py、sql/query.py中完成 legacy alias 到 DRF 视图或复用服务层的 wrapper的路由绑定。设计原则页面优先继续使用现有 URL 与响应 envelope后端把 legacy route 指向 DRF view 或兼容 wrapper。只有 legacy 路由全局复用成本过高时才在 sql/templates/sqlquery.html 做集中式 URL 替换见 plan.md Frontend compatibility strategy。3.1 响应 envelope 的按端点兼容策略Quickstart 与 research.mdDecision 3明确指出响应兼容是 per-endpoint 的不是全局统一因为页面中不同 AJAX 回调依赖不同结构执行查询execute与收藏favorites保留status/msg/data风格查询历史logs保留total/rows直接满足 bootstrap-table 的分页解析实例/资源列表instances/resources保留status/msg/data。tasks.md 中 T016、T022、T023、T026 均明确要求保持这些兼容结构如 返回total/rows兼容结构、返回status/msg兼容结构。对应实现中sql_api/sqlquery_response.py 提供了统一的 envelope 工具函数def envelope(status0, msgok, dataNone): if data is None: data [] return {status: status, msg: msg, data: data} def envelope_response(status0, msgok, dataNone, http_status200): return Response(envelope(statusstatus, msgmsg, datadata), statushttp_status)4. 请求示例与参数详解以下示例全部来自 Quickstart 文档并结合 contracts/sqlquery-api.openapi.yaml 与 sql_api/serializers.py 的序列化器定义补充参数说明。4.1 获取可访问实例列表GET /api/v1/sqlquery/instances/?tag_codescan_readtype可选实例类型db_type可选数组引擎类型用于分组下拉选项tag_codes可选数组资源标签过滤如can_read、can_write。对应序列化器SqlQueryInstancesQuerySerializersql_api/serializers.py将其解析为ListField。视图通过_get_list_values兼容db_type与db_type[]两种传参形式。服务层 sql/services/resource_service.py 内部调用user_instances(user, type, db_type, tag_codes)并按instance_name的 GBK 排序返回id/type/db_type/instance_name四字段契约AccessibleInstanceItem字段名与旧接口保持一致避免前端重新映射。4.2 获取某实例下的数据库列表GET /api/v1/sqlquery/resources/?instance_nametest-mysqlresource_typedatabaseinstance_name必填与instance_id二选一目标实例legacy 兼容路径主要使用instance_nameinstance_id可选规范化 API 也可用目标实例主键resource_type必填枚举database/schema/table/column/server_infodb_name可选resource_typetable时必填schema_name可选为 PgSQL 表读取保留的兼容字段tb_name可选resource_typecolumn时必填。序列化器SqlQueryResourceQuerySerializersql_api/serializers.py的校验规则instance_id与instance_name至少提供一个table/schema类型要求db_name非空column类型要求同时提供db_name与tb_name。4.3 获取某实例/数据库下的表列表GET /api/v1/sqlquery/resources/?instance_nametest-mysqldb_namearcheryresource_typetable服务层list_instance_resourcessql/services/resource_service.py的行为链路通过user_instances(user)解析实例解析失败返回{status: 1, msg: 实例不存在或无权限}避免泄露目标资源详情通过get_engine(instance)获取对应数据库引擎适配器对db_name/schema_name/tb_name做escape_string转义按resource_type分派database走get_all_databases()并叠加show_db_name_regex/denied_db_name_regex正则过滤filter_db_listtable走get_all_tables(db_name, schema_nameschema_name)引擎返回error时置status1否则data resource.rows扁平数组。这一链路印证了 plan.md 的 Constitution Check查询执行、database/table 资源读取仍统一走sql.engines.get_engine()与既有 adapter不在 DRF 层引入引擎分支——多引擎兼容性完全收敛在引擎适配层。4.4 执行查询POST /api/v1/sqlquery/execute/ { instance_name: test-mysql, db_name: archery, schema_name: , tb_name: sql_workflow, sql_content: select 1;, limit_num: 100 }请求字段契约SqlQueryExecutionRequestcontracts/sqlquery-api.openapi.yaml字段必填说明instance_name是目标实例名db_name是目标数据库名sql_content是待执行 SQL 文本limit_num是序列化器默认 0返回行数上限最小 0schema_name否PgSQL 兼容字段tb_name否目标表名对应序列化器SqlQueryExecuteSerializersql_api/serializers.py要求instance_name、db_name、sql_content必填limit_num为min_value0的整数。底层执行链路sql/services/sqlquery_service.py完整保留了旧/query/的服务端安全控制对应 spec 的 FR-004limit_num合法性校验非法返回limit_num 非法实例访问校验user_instances(user).get(instance_nameinstance_name)失败返回你所在组未关联该实例语句合法性校验query_engine.query_check(db_name, sql)命中bad_query直接拒绝命中has_star且系统配置disable_starTrue时拒绝通过后取filtered_sql查询权限校验query_priv_check(user, instance, db_name, sql_content, limit_num)见 sql/query_privileges.py失败返回对应错误成功后得到effective limit_num与priv_check标记行数限制explain开头的语句limit_num置 0否则query_engine.filter_sql(sql, limit_num)改写 SQL超时终止建立连接后取thread_id读取系统配置max_execution_time默认 60 秒通过add_kill_conn_schedule注册 kill 调度查询完成或出错后del_schedule清理同时把max_execution_time * 1000作为引擎级超时毫秒数传入执行与计时FuncTimer包裹query_engine.query(...)记录query_time同时取seconds_behind_master主从延迟结果脱敏系统配置data_masking开启时调用query_engine.query_masking(...)脱敏失败且query_check开启则拒绝返回数据脱敏异常否则降级放行原始结果审计留痕执行成功后QueryLog.objects.create(...)记录 username、user_display、db_name、instance_name、sqllog、effect_rowmin(limit_num, affected_rows)、cost_time、priv_check、mask_rule_hit、is_masked。响应结构契约SqlQueryExecutionResponse{status, msg, data}其中data包含column_list、rows、query_time、mask_time、full_sql、seconds_behind_master、error以及引擎相关的其他字段直接来自query_result.__dict__见>GET /api/v1/sqlquery/logs/?limit20offset0searchselect查询参数SqlQueryLogsQuerySerializersql_api/serializers.py参数默认说明limit0分页条数0 表示不分页offset0分页偏移search关键字对 sqllog / user_display / alias 做 icontains 匹配startrue时仅返回收藏记录query_log_id无精确指定某条记录start_date/end_date创建时间范围YYYY-MM-DDend 自动 1 天服务层 sql/services/querylog_service.py 的关键行为limit offset limit按-id倒序切片返回{total: count, rows: [...]}的 bootstrap-table 兼容结构普通用户强制filter_dict[username] user.username审计角色与超级用户可见更广范围角色差异对应 spec 的 FR-012 与 Quickstart 第 5 步验证点行记录字段与契约QueryLogItem一致id、instance_name、db_name、sqllog、effect_row、cost_time、user_display、favorite、alias、create_time字段名不变以便复用前端 bootstrap-table 列配置。4.6 收藏 / 取消收藏一条查询记录POST /api/v1/sqlquery/favorites/ { query_log_id: 123, star: true, alias: 常用检查语句 }请求字段契约FavoriteMutationRequestquery_log_id必填最小 1、star必填布尔或字符串序列化器统一转str(value).lower() true、alias可选默认空串。服务层update_favoritesql/services/querylog_service.py的写权限校验普通用户只能修改username为自己的记录否则返回{status: 1, msg: 查询记录不存在或无权限}且不改变原始记录成功后query_set.update(favoritestar, aliasalias)并返回{status: 0, msg: ok}。5. 手工验证流程Quickstart 文档给出了 6 步手工验收路径与 spec 的 Acceptance Scenarios 一一对应实例加载使用具备 SQL 查询页面权限的普通用户登录打开/sqlquery/确认实例下拉框仍能加载当前用户有权访问的实例对应 US3 场景验证user_instances过滤级联加载选择一个实例后确认 database 列表能正常加载再选择一个 database确认 table 列表能正常加载对应resource_typedatabase/table的资源链路查询执行输入一条允许的查询语句并执行确认结果页仍能展示数据、耗时query_time、脱敏时间mask_time和主从延迟信息seconds_behind_master对应 US1 核心主流程历史分页与搜索打开查询历史确认 bootstrap-table 仍能显示分页数据并支持搜索、按收藏筛选和一键重查对应limit/offset/search/star/query_log_id参数收藏与别名在历史记录中收藏和取消收藏一条 SQL确认状态和别名都能正确刷新对应 favorites 接口的star/alias变更权限拒绝使用无相应权限的用户重复调用上述接口确认被拒绝且返回可读错误而不是 DRF 默认 HTML/JSON 异常页对应权限模型与可读 envelope 设计。补充建议按 spec.md 的 Edge Cases验证时还应覆盖打开页面后权限发生变化再请求必须按最新权限立即拒绝、目标实例/数据库不存在必须返回清晰反馈等边界场景。6. 聚焦测试命令Quickstart 给出的两条核心测试命令pytest -q sql_api/test_sqlquery_api.py pytest -q sql/tests.py -k sqlquery or query_log or star第一条覆盖 sql_api/test_sqlquery_api.pySQLQuery 场景的 serializer、service、permission 与 envelope 单元测试外加 DRF auth wiring、legacy alias 路由绑定、Session 登录场景的少量集成测试对应 tasks.md 中 T012/T013/T014、T019/T020/T021、T027/T028/T029 等任务第二条覆盖 sql/tests.py保留的页面 smoke 与 legacy URL 回归对应 T018、T026、T033重点锁定total/rows与status/msg兼容行为。6.1 测试策略约束依据 spec 的 TSC-001 ~ TSC-004 与 research.md Decision 7测试遵循unit-first、共享夹具、最小集成原则优先用 pytest 单元测试验证 serializer、permission、service 与 envelope 兼容共享测试准备通过 conftest.py 或可复用夹具统一管理复用用户、实例、权限、QueryLog、fake engine fixture避免在sql_api与sql/tests.py重复初始化见 plan.md Constitution Check 第 3 条集成测试仅用于跨越认证、权限、视图与现有查询引擎边界的关键行为如统一授权是否真正生效且每条集成测试必须附注释说明为什么单元测试不足以证明其余执行路径优先通过 fake engine / monkeypatch 的方式验证即 Quickstart 文档末尾的 Integration-test note。7. 实施任务编排与并行策略tasks.md 将实现拆分为 6 个阶段其中Phase 1 Setup创建服务层骨架sql/services/sqlquery_service.py、sql/services/querylog_service.py、sql/services/resource_service.py、测试文件与响应封装工具 sql_api/sqlquery_response.pyPhase 2 Foundational阻塞性前置页面场景权限类、6 个接口的 serializer、DRF 视图骨架、canonical 路由注册、legacy alias 绑定Phase 3/4/5User Stories可按优先级交付US1 安全执行查询P1MVP→ US2 历史与收藏P2→ US3 实例与表元数据P3Phase 6 Polish更新契约与文档、回归测试收口。阶段内可并行任务以[P]标记如 T003、T005、T006、T010、T011阶段间存在明确依赖Phase 2 完成前不得开始任何用户故事实现见 tasks.md 的 ⚠️ CRITICAL 提示。8. 迁移后的核心收益与边界说明从 plan.md 与 research.md 可以归纳本次迁移的技术收益与明确边界收益查询页面 6 项后端能力统一收敛到 DRF 接口层认证方式、权限校验与资源范围控制整组一致FR-002后端集中改造优先前端仅做必要的最小兼容适配sqlquery.html的 URL/参数调整规范化/api/v1/sqlquery/*路径配合 OpenAPI 契约长期可发现性与文档性更好业务逻辑抽取到服务层后查询执行、资源读取与历史收藏均可独立单元测试。边界本次不涉及见 spec Assumptions表结构查看describetable、AI 生成 SQL、线下导出工单与查询权限申请不在 6 接口核心范围内不重新设计查询引擎、脱敏逻辑、权限规则、审计记录与 AI 生成能力全部复用现有实现schema_name仅作为 PgSQL 兼容的可选字段保留不把schema 读取列为独立迁移能力页面本身保留现有入口与交互方式只做适配迁移所需的最小改动。附关键文件索引文件内容quickstart.md接口清单、请求示例、验证流程、测试命令spec.md用户故事、功能需求、成功标准、边界plan.md技术方案、结构决策、阶段划分research.md关键技术决策记录data-model.md7 个核心数据实体与校验规则tasks.md任务清单、依赖与并行策略contracts/sqlquery-api.openapi.yamlOpenAPI 3.0 契约sql_api/api_sqlquery.pySQLQuery DRF 视图实现sql_api/serializers.py请求/响应序列化器sql_api/sqlquery_response.pyenvelope 工具sql/services/sqlquery_service.py查询执行服务sql/services/querylog_service.py历史与收藏服务sql/services/resource_service.py实例/资源读取服务sql_api/test_sqlquery_api.py聚焦测试赞分享后端数据库【免费下载链接】ArcherySQL 审核查询平台项目地址https://gitcode.com/gh_mirrors/ar/Archery点击查看免费下载相关推荐sqlmap跑了十分钟什么都没报出来之后我换了一套CyberStrikeAI的SQL注入检测思路sqlmap跑了十分钟什么都没报出来之后我换了一套CyberStrikeAI的SQL注入检测思路 你往参数后面加个单引号页面直接500但sqlmap跑了十后端数据库fetchbot扩展开发指南如何实现自定义的URL去重和深度控制策略fetchbot扩展开发指南如何实现自定义的URL去重和深度控制策略 fetchbot是一个灵活且强大的Go语言网页爬虫框架专为遵循robots.txt策略后端从Elasticsearch迁移到Manticore SearchES兼容接口迁移完整手册从Elasticsearch迁移到Manticore SearchES兼容接口迁移完整手册 Manticore Search 是一个开源的搜索数据库支持全文搜索引擎数据库全文检索后端上一篇PDF Arranger入门指南5分钟学会PDF页面合并与分割下一篇ComfyUI视频生成终极指南5分钟快速部署WanVideo完整工作流创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考