Baserow 后端分层架构实战:以 Automation 模块为范式打通 Model、Handler、Service、Action 与 API
2026/9/17 8:07:35 网站建设 项目流程

Baserow 后端分层架构实战:以 Automation 模块为范式打通 Model、Handler、Service、Action 与 API

【免费下载链接】baserowBuild databases, automations, apps & agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alternative.项目地址: https://gitcode.com/GitHub_Trending/ba/baserow

本指南基于 Baserow 仓库内置的manage-backend-layers技能文档,系统讲解其后端功能分层的职责边界、实现顺序与协作模式,并以automation(自动化)模块为首选范式。读完本文,你将掌握如何为模型驱动的 CRUD/领域功能正确划分 Django models、handler.pyservice.py、可撤销的actions.py、API serializers/errors/views/URLs 以及权限、信号、迁移与测试的职责,并能在新增后端功能时快速定位最近的可参照模块。

一、分层总览:为什么 Baserow 强制分层

Baserow 后端是典型的「职责分离」架构。当一个后端改动横跨多个层(新增模型、改领域持久化、加用户侧可撤销操作、暴露 REST API 等)时,manage-backend-layers技能要求严格遵循以下分层,这是整个技能的核心规则

文件惯例核心职责
Modelsmodels.py持久化、关系、管理器、排序、mixin、小型模型内辅助方法
Handlershandler.py领域逻辑与持久化,不假设已认证用户的权限上下文
Servicesservice.py面向用户的应用层:接收user、校验权限、调用 handler、发信号、协调关联领域 handler
Actionsactions.py用户侧可变操作的可撤销类型(undo/redo)
APIapi/*/serializers.pyerrors.pyviews.pyurls.py输入校验、异常映射、调用 action/service、输出序列化

技能的官方首选模式来源是较新的 automation 模块:

  • 工作流:backend/src/baserow/contrib/automation/workflows/
  • 节点:backend/src/baserow/contrib/automation/nodes/
  • 工作流 API 视图:backend/src/baserow/contrib/automation/api/workflows/views.py
  • 节点 API 视图:backend/src/baserow/contrib/automation/api/nodes/views.py

下文每一层都以 automation 模块的真实实现为证据展开。

二、第一件事:识别特性表面并寻找最近的参照模块

动手编辑前,先回答四个问题,确定「特性表面」(feature surface):

  1. 这是新的模型支撑概念,还是对既有模型的修改?
  2. 行为是纯领域持久化、用户侧可变、可撤销、API 暴露,还是全部兼有?
  3. 是否需要权限、workspace 作用域、信号、回收站(trash)、导入导出、排序或特定的类型化子类?
  4. 是否存在接近的 automation 工作流/节点模式,或者目标 app 中更接近的模式?

技能文档推荐使用以下搜索命令快速定位参照:

grep -RInE "class .*Handler|class .*Service|UndoableActionType|APIView" backend/src/baserow/contrib/automation grep -RInE "check_permissions|filter_queryset" backend/src/baserow/contrib/automation grep -RInE "@transaction.atomic|@map_exceptions|@validate_body|@require_request_data_type" backend/src/baserow grep -RInE "ActionTypeDescription|register_action|def undo|def redo" backend/src/baserow grep -RInE "objects_and_trash|TrashHandler|TrashableModelMixin|OrderableMixin" backend/src/baserow

rg可用时,可用rg -n "<pattern>" <paths>作为更快的等价命令。

三、Models 层:只做持久化与模型内辅助

模型层定义持久化、关系、管理器、排序、mixin 与小的模型内辅助方法。参考模式位于 automation/workflows/models.py 与 automation/nodes/models.py。

3.1 复用现成 mixin

Baserow 提供一组可复用的核心 mixin,automation 的AutomationWorkflow模型是它们的集大成者:

class AutomationWorkflow( HierarchicalModelMixin, # 层级树:get_parent() 返回所属 automation TrashableModelMixin, # 可回收站化 CreatedAndUpdatedOnMixin, # 自动维护 created_on / updated_on OrderableMixin, # 排序:get_last_order / order_objects GraphModelMixin, # 工作流图(节点与边的连接) ): automation = models.ForeignKey( "automation.Automation", on_delete=models.CASCADE, related_name="workflows" ) name = models.CharField(max_length=WORKFLOW_NAME_MAX_LEN) state = models.CharField(choices=WorkflowState.choices, default=WorkflowState.DRAFT, ...) order = models.PositiveIntegerField() ...

get_parent()返回所属 automation,使模型自动获得层级作用域能力。

3.2 回收站管理器:objects_and_trash

当被删除行仍需可寻址时(例如恢复、重名检测),按文档要求添加objects_and_trash = models.Manager()AutomationWorkflow同时自定义了一个默认管理器,自动排除所有被回收的关系链:

class AutomationWorkflowTrashManager(models.Manager): def get_queryset(self): return ( super().get_queryset().exclude( models.Q(trashed=True) | models.Q(automation__trashed=True) | models.Q(automation__workspace__trashed=True) ) ) class AutomationWorkflow(...): objects = AutomationWorkflowTrashManager() objects_and_trash = models.Manager()

AutomationNode的做法与此一致(见 automation/nodes/models.py),且额外组合了PolymorphicContentTypeMixinWithRegistry以支持触发器/动作节点的类型化多态注册。

3.3 模型层清单

  1. 添加字段、约束、索引、related name 与管理器;
  2. 相关时使用既有 mixin:CreatedAndUpdatedOnMixinOrderableMixinTrashableModelMixinHierarchicalModelMixin
  3. 被删除行需要可寻址时加objects_and_trash = models.Manager()
  4. 跨对象的业务工作流不要放进模型,除非邻近代码已有先例;
  5. 任何 schema 变更都要伴随迁移。

四、Handlers 层:纯领域逻辑与持久化

Handler 拥有领域逻辑与持久化,不假设已认证用户的权限上下文。参考模式为 automation/workflows/handler.py 与 automation/nodes/handler.py。

4.1 典型职责

  • 获取对象并抛出领域异常(如AutomationWorkflowDoesNotExist);
  • 构造 queryset,使用select_relatedprefetch_relatedspecific_iterator
  • create/update/delete 持久化;
  • extract_allowed、allowed field 列表、m2m 处理;
  • 复制、导入导出、排序、缓存失效、回收站机制;
  • 需要支持 undo 时,返回「原始值/新值」的类型化结果对象。

AutomationWorkflowHandler为例(handler.py):

@baserow_trace_handler class AutomationWorkflowHandler: allowed_fields = [ "name", "allow_test_run_until", "state", "notification_recipients", ]

allowed_fields是白名单,配合extract_allowed(kwargs, self.allowed_fields)过滤更新入参;m2m 字段通过split_attrs_and_m2m_fields拆分后用set_allowed_m2m_fields落库。

4.2 用类型化返回值支持 undo/redo

update_workflow在更新前后各调用一次export_prepared_values,返回UpdatedAutomationWorkflow(workflow, original_values, new_values)供上层 action 记录撤销元数据——这正是技能文档所说的「returning typed result objects for original/new values when useful for undo」:

def update_workflow(self, workflow, **kwargs) -> UpdatedAutomationWorkflow: original_workflow_values = self.export_prepared_values(workflow) allowed_values = extract_allowed(kwargs, self.allowed_fields) ... workflow.save() set_allowed_m2m_fields(allowed_values, m2m_fields, workflow) new_workflow_values = self.export_prepared_values(workflow) return UpdatedAutomationWorkflow(workflow, original_workflow_values, new_workflow_values)

Handler 还承担了发布(publish,通过导出/导入克隆出一个 LIVE 副本)、测试运行(toggle_test_run/set_workflow_temporary_states)、运行前置检查(before_run,含限流与连续错误熔断)、历史清理(clear_old_history)等纯领域能力。

4.3 Handler 中的禁忌

  • 不要调用CoreHandler().check_permissions(...)
  • 不要接触 request 对象、API serializer 或响应组装;
  • 不要注册 undo action;
  • 除非既有模块的 handler 明确拥有,否则不要产生宽泛副作用。

五、Services 层:用户可见的应用编排层

Service 是面向用户的后端应用层,通常接收user、检查权限、调用 handler、发送信号并协调相关领域 handler。参考模式为 automation/workflows/service.py 与 automation/nodes/service.py。

5.1 权限检查与 queryset 过滤

Service 是唯一应调用CoreHandler().check_permissions(...)CoreHandler().filter_queryset(...)的层。AutomationWorkflowService.get_workflow展示了标准形态:

def get_workflow(self, user, workflow_id) -> AutomationWorkflow: workflow = self.handler.get_workflow(workflow_id) CoreHandler().check_permissions( user, ReadAutomationWorkflowOperationType.type, workspace=workflow.automation.workspace, context=workflow, ) return workflow

列表场景用filter_queryset按权限裁剪 queryset(list_workflowsorder_workflows均如此)。权限点对应 workflows/operations.py 中定义的 operation type,例如automation.workflow.readautomation.workflow.updateautomation.workflow.deleteautomation.workflow.duplicateautomation.publish_workflow等。文档明确提醒:不要跳过 operation type 就引入新的用户可见能力;若任务涉及权限,还应配合Manage Baserow Permissions技能。

5.2 其他 Service 职责

  • 将 API 面向的 ID 映射为模型关系(如_map_notification_recipient_idsnotification_recipient_ids映射为 workspace 内的用户实例,并校验「所有通知接收者必须属于该 workspace」,否则抛AutomationWorkflowNotificationRecipientsInvalid);
  • 校验 workspace 成员身份或跨对象约束;
  • 权限通过后调用 handler;
  • 成功变更后发送领域信号(automation_workflow_createdautomation_workflow_updatedautomation_workflow_deletedautomation_workflow_publishedautomation_workflows_reordered,见 workflows/signals.py);
  • 协调缓存、图、集成、通知或关联对象更新。

5.3 关键约束

Service 必须保持「可从 API 视图、action type、job 和测试中调用」,且不得从 service 返回 DRF response

六、Actions 层:可撤销的用户侧操作

用户侧的可变操作若需参与 undo/redo 或操作历史,必须使用UndoableActionType。参考模式为 automation/workflows/actions.py 与 automation/nodes/actions.py。

6.1 Action 的标准骨架

CreateAutomationWorkflowActionType为例,它完整展示了技能的六个检查点:

class CreateAutomationWorkflowActionType(UndoableActionType): type = "create_automation_workflow" # 1. 稳定的 type 字符串 description = ActionTypeDescription( # 2. 人类可读描述 _("Create automation workflow"), _('Workflow "%(workflow_name)s" (%(workflow_id)s) created'), AUTOMATION_ACTION_CONTEXT, ) @dataclass class Params: # 2. dataclass 参数 automation_id: int automation_name: str workflow_id: int workflow_name: str @classmethod def do(cls, user, automation_id, data) -> AutomationWorkflow: workflow = AutomationWorkflowService().create_workflow(user, automation_id, **data) cls.register_action( # 3. 调用 service 后注册 action user=user, params=cls.Params( workflow.automation.id, workflow.automation.name, workflow.id, workflow.name, ), scope=cls.scope(workflow.automation.id), # 5. 就近作用域(application) workspace=workflow.automation.workspace, ) return workflow @classmethod def scope(cls, automation_id): return ApplicationActionScopeType.value(automation_id) @classmethod def undo(cls, user, params, action_to_undo): AutomationWorkflowService().delete_workflow(user, params.workflow_id) @classmethod def redo(cls, user, params, action_to_redo): TrashHandler.restore_item( # 6. 复用 trash 恢复,而非重写持久化 user, AutomationWorkflowTrashableItemType.type, params.workflow_id, )

检查点对应关系:稳定的typeActionTypeDescription+ dataclassParamsdo()调 service 后register_action、params 中存足 undo/redo 所需 ID 与原始/新值、作用域就近取用(多为 application 或 workspace scope)、undo/redo调用 service 或 trash 恢复助手而不重复持久化逻辑。

UpdateAutomationWorkflowActionType的 params 中直接保存workflow_original_paramsworkflow_new_params,undo/redo 时用同一update_workflowservice 调用回放旧值/新值——这正是「存够参数才能确定性地撤销与重做」的体现。

6.2 何时不必用 Action

仅当操作是内部的、只读的、非用户可见的,或邻近代码并未将类似变更做成可撤销时,才直接调用 service 而不包装 action。

七、API 层:薄而明确的视图

视图应薄而明确:校验输入、映射异常、调用 action/service、序列化输出、返回响应。参考模式位于 automation/api/workflows/(serializers、errors、views、urls)与 automation/api/nodes/。

7.1 一个典型的 CRUD 视图

automation/api/workflows/views.py 中的AutomationWorkflowsView.post完整演示了 API 层清单:

class AutomationWorkflowsView(APIView): permission_classes = (IsAuthenticated,) @extend_schema( # 3. OpenAPI:operation id、tags、参数、请求/响应 schema parameters=[OpenApiParameter(name="automation_id", ...), CLIENT_SESSION_ID_SCHEMA_PARAMETER], tags=[AUTOMATION_WORKFLOWS_TAG], operation_id="create_automation_workflow", request=CreateAutomationWorkflowSerializer, responses={ 200: AutomationWorkflowSerializer, 400: get_error_schema(["ERROR_AUTOMATION_WORKFLOW_NOTIFICATION_RECIPIENTS_INVALID", ...]), 404: get_error_schema(["ERROR_APPLICATION_DOES_NOT_EXIST"]), }, ) @transaction.atomic # 4. 变更包在事务中 @map_exceptions( # 5. 领域异常 -> API 错误常量 { ApplicationDoesNotExist: ERROR_APPLICATION_DOES_NOT_EXIST, AutomationWorkflowNotificationRecipientsInvalid: ( ERROR_AUTOMATION_WORKFLOW_NOTIFICATION_RECIPIENTS_INVALID ), } ) @validate_body(CreateAutomationWorkflowSerializer, return_validated=True) # 6. 简单 serializer 校验 def post(self, request, data, automation_id): workflow = CreateAutomationWorkflowActionType.do(request.user, automation_id, data) # 8. 可撤销变更走 action return Response(AutomationWorkflowSerializer(workflow).data)

同一文件中,读取走 service(getAutomationWorkflowService().get_workflow),更新/删除走 action(UpdateAutomationWorkflowActionType.do/DeleteAutomationWorkflowActionType.do),异步复制与发布通过JobHandler().create_and_start_job返回202AsyncAutomationDuplicateWorkflowViewAsyncPublishAutomationWorkflowView),测试运行通过AutomationWorkflowService().toggle_test_run返回202。这些路由最后在 automation/api/workflows/urls.py 中注册,必要时还要挂到上层 API URL 文件。

7.2 错误常量

领域异常到 HTTP 错误的映射常量集中定义在 automation/api/workflows/errors.py,每个常量是「错误码 + HTTP 状态 + 消息模板」三元组,例如:

ERROR_AUTOMATION_WORKFLOW_DOES_NOT_EXIST = ( "ERROR_AUTOMATION_WORKFLOW_DOES_NOT_EXIST", HTTP_404_NOT_FOUND, "The requested workflow does not exist.", ) ERROR_AUTOMATION_WORKFLOW_NOT_IN_AUTOMATION = ( "ERROR_AUTOMATION_WORKFLOW_NOT_IN_AUTOMATION", HTTP_400_BAD_REQUEST, "The workflow id {e.workflow_id} does not belong to the automation.", )

技能强调:不要不映射领域异常就把模型变更暴露到 API 视图。类型化/多态模型还应使用 registry discriminator 辅助器(如 automation 的automation_node_type_registry)。

八、权限 + 信号的通用模式

对权限感知的变更,技能的推荐形态是一条明确的调用链:

  1. Service 通过 handler 获取父对象或目标对象;
  2. Service 调用CoreHandler().check_permissions(...),传入具体 operation type、workspace 与 context;
  3. Service 校验跨对象约束;
  4. Service 调用 handler 的变更方法;
  5. Service 成功后发送领域信号;
  6. Action 包装 service 调用并注册 undo 元数据;
  7. 视图在transaction.atomic内调用 action。

AutomationWorkflowService.update_workflow为例,上述第 1~5 步逐一可见:handler.get_workflowcheck_permissions(UpdateAutomationWorkflowOperationType.type, ...)_map_notification_recipient_ids校验 →handler.update_workflowautomation_workflow_updated.send(...)。对应的 APIPATCH视图再以@transaction.atomic+UpdateAutomationWorkflowActionType.do完成第 6、7 步。

九、实现顺序:新增功能与改造既有功能

9.1 新增模型支撑的 CRUD/领域功能

按以下顺序实现(技能文档明确给出的工作顺序):

  1. Model 与领域异常;
  2. Handler 方法(含 allowed fields,必要时含类型化返回值);
  3. Operation types 与权限行为;
  4. Service 方法(含权限检查与信号);
  5. 用户侧变更的可撤销 action types;
  6. API serializers、errors、views 与 URLs;
  7. apps.py、registries、trash/search/object scope 模块或 signal receivers 中注册;
  8. 迁移;
  9. 测试。

9.2 改造既有功能

先沿「URL → view → action/service → handler → model」追踪既有调用链,再只修补拥有该行为的最窄层,避免为了「新抽象」而重构。

十、测试:以最窄用例起步

详细测试约定由Write Baserow Backend Tests技能提供;本文档要求至少新增或更新以下聚焦测试:

  • handler 的 create/update/delete 或排序行为;
  • service 的权限检查与信号副作用;
  • 涉及 action 时的 undo/redo 行为;
  • API 的状态码、校验、异常映射与响应结构;
  • 依赖既有数据行的迁移或数据回填。

自动化模块的测试位置参考:

  • backend/tests/baserow/contrib/automation/workflows/(test_actions.pytest_workflow_handler.pytest_workflow_service.pytest_graph_handler.py等)
  • backend/tests/baserow/contrib/automation/nodes/
  • backend/tests/baserow/contrib/automation/api/

以 backend/tests/baserow/contrib/automation/workflows/test_actions.py 为例,test_create_undo验证CreateAutomationWorkflowActionType.do后调用undo会使automation.workflows.count()归零,test_create_redo进一步验证redo通过 trash 恢复让工作流重新出现——完整覆盖了「action 注册 → 撤销 → 重做」的可逆闭环。

先跑最窄的后端测试(just b test ...是 Baserow 的标准测试入口):

just b test tests/baserow/contrib/automation/workflows/ just b test tests/baserow/contrib/automation/nodes/ just b test tests/path/to/test_file.py

十一、Guardrails:不可逾越的红线

技能文档以一组明确禁令收尾,实践中最容易踩坑的几条:

  • 不在 handler 里放权限检查,除非目标模块已有该旧模式且改造超出本次范围;
  • 不跨层重复变更逻辑:视图、action、service、handler 各司其职,逐层向下委托;
  • 不注册参数不足以确定性撤销/重做的可撤销 action
  • 不在未映射领域异常的情况下通过 API 视图暴露模型变更
  • 不加模型字段却不加迁移,用just b manage makemigrations --check校验;
  • 权限检查不忘 queryset 作用域与workspace上下文
  • 不随意重命名已持久化的 action type、operation type 或 API 路由
  • 优先复用最近的既有模块模式,而非引入新抽象

结语

Baserow 后端的分层不是形式主义:Models 守住持久化边界,Handlers 沉淀纯领域逻辑,Services 统一权限与信号编排,Actions 让用户操作可回溯,API 层保持薄而明确。automation 模块(workflows 与 nodes)就是这套模式的最佳范本——新增后端功能时,先回答「特性表面」四个问题,再按实现顺序逐层落地,最后用最窄的测试用例验证每一层的行为,即可在不破坏既有架构的前提下高质量地扩展 Baserow 后端能力。

【免费下载链接】baserowBuild databases, automations, apps & agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alternative.项目地址: https://gitcode.com/GitHub_Trending/ba/baserow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询