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.py、service.py、可撤销的actions.py、API serializers/errors/views/URLs 以及权限、信号、迁移与测试的职责,并能在新增后端功能时快速定位最近的可参照模块。
一、分层总览:为什么 Baserow 强制分层
Baserow 后端是典型的「职责分离」架构。当一个后端改动横跨多个层(新增模型、改领域持久化、加用户侧可撤销操作、暴露 REST API 等)时,manage-backend-layers技能要求严格遵循以下分层,这是整个技能的核心规则:
| 层 | 文件惯例 | 核心职责 |
|---|---|---|
| Models | models.py | 持久化、关系、管理器、排序、mixin、小型模型内辅助方法 |
| Handlers | handler.py | 领域逻辑与持久化,不假设已认证用户的权限上下文 |
| Services | service.py | 面向用户的应用层:接收user、校验权限、调用 handler、发信号、协调关联领域 handler |
| Actions | actions.py | 用户侧可变操作的可撤销类型(undo/redo) |
| API | api/*/serializers.py、errors.py、views.py、urls.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):
- 这是新的模型支撑概念,还是对既有模型的修改?
- 行为是纯领域持久化、用户侧可变、可撤销、API 暴露,还是全部兼有?
- 是否需要权限、workspace 作用域、信号、回收站(trash)、导入导出、排序或特定的类型化子类?
- 是否存在接近的 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),且额外组合了PolymorphicContentTypeMixin与WithRegistry以支持触发器/动作节点的类型化多态注册。
3.3 模型层清单
- 添加字段、约束、索引、related name 与管理器;
- 相关时使用既有 mixin:
CreatedAndUpdatedOnMixin、OrderableMixin、TrashableModelMixin、HierarchicalModelMixin; - 被删除行需要可寻址时加
objects_and_trash = models.Manager(); - 跨对象的业务工作流不要放进模型,除非邻近代码已有先例;
- 任何 schema 变更都要伴随迁移。
四、Handlers 层:纯领域逻辑与持久化
Handler 拥有领域逻辑与持久化,不假设已认证用户的权限上下文。参考模式为 automation/workflows/handler.py 与 automation/nodes/handler.py。
4.1 典型职责
- 获取对象并抛出领域异常(如
AutomationWorkflowDoesNotExist); - 构造 queryset,使用
select_related、prefetch_related、specific_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_workflows、order_workflows均如此)。权限点对应 workflows/operations.py 中定义的 operation type,例如automation.workflow.read、automation.workflow.update、automation.workflow.delete、automation.workflow.duplicate、automation.publish_workflow等。文档明确提醒:不要跳过 operation type 就引入新的用户可见能力;若任务涉及权限,还应配合Manage Baserow Permissions技能。
5.2 其他 Service 职责
- 将 API 面向的 ID 映射为模型关系(如
_map_notification_recipient_ids把notification_recipient_ids映射为 workspace 内的用户实例,并校验「所有通知接收者必须属于该 workspace」,否则抛AutomationWorkflowNotificationRecipientsInvalid); - 校验 workspace 成员身份或跨对象约束;
- 权限通过后调用 handler;
- 成功变更后发送领域信号(
automation_workflow_created、automation_workflow_updated、automation_workflow_deleted、automation_workflow_published、automation_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, )检查点对应关系:稳定的type、ActionTypeDescription+ dataclassParams、do()调 service 后register_action、params 中存足 undo/redo 所需 ID 与原始/新值、作用域就近取用(多为 application 或 workspace scope)、undo/redo调用 service 或 trash 恢复助手而不重复持久化逻辑。
UpdateAutomationWorkflowActionType的 params 中直接保存workflow_original_params与workflow_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(get→AutomationWorkflowService().get_workflow),更新/删除走 action(UpdateAutomationWorkflowActionType.do/DeleteAutomationWorkflowActionType.do),异步复制与发布通过JobHandler().create_and_start_job返回202(AsyncAutomationDuplicateWorkflowView、AsyncPublishAutomationWorkflowView),测试运行通过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)。
八、权限 + 信号的通用模式
对权限感知的变更,技能的推荐形态是一条明确的调用链:
- Service 通过 handler 获取父对象或目标对象;
- Service 调用
CoreHandler().check_permissions(...),传入具体 operation type、workspace 与 context; - Service 校验跨对象约束;
- Service 调用 handler 的变更方法;
- Service 成功后发送领域信号;
- Action 包装 service 调用并注册 undo 元数据;
- 视图在
transaction.atomic内调用 action。
以AutomationWorkflowService.update_workflow为例,上述第 1~5 步逐一可见:handler.get_workflow→check_permissions(UpdateAutomationWorkflowOperationType.type, ...)→_map_notification_recipient_ids校验 →handler.update_workflow→automation_workflow_updated.send(...)。对应的 APIPATCH视图再以@transaction.atomic+UpdateAutomationWorkflowActionType.do完成第 6、7 步。
九、实现顺序:新增功能与改造既有功能
9.1 新增模型支撑的 CRUD/领域功能
按以下顺序实现(技能文档明确给出的工作顺序):
- Model 与领域异常;
- Handler 方法(含 allowed fields,必要时含类型化返回值);
- Operation types 与权限行为;
- Service 方法(含权限检查与信号);
- 用户侧变更的可撤销 action types;
- API serializers、errors、views 与 URLs;
- 在
apps.py、registries、trash/search/object scope 模块或 signal receivers 中注册; - 迁移;
- 测试。
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.py、test_workflow_handler.py、test_workflow_service.py、test_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),仅供参考