资讯动态

Baserow 插件开发指南:实现自定义视图过滤器类型(View Filter Type)

发布时间:2026/9/17 9:06:37 来源:尧图企业网站定制
Baserow 插件开发指南实现自定义视图过滤器类型View Filter Type【免费下载链接】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视图过滤器View Filter允许用户按字段条件筛选视图中的行——只有满足全部过滤条件的行才会被显示。Baserow 将这些过滤条件抽象为可注册的“过滤器类型”如 equal、contains、is lower than、is empty 等并允许插件作者通过插件机制扩展全新的过滤器类型。本文基于仓库中的 view-filter-type 插件教程结合后端ViewFilterType抽象类与前端ViewFilterType基类的真实源码实现完整讲解如何从零实现一个自定义视图过滤器包括后端get_filter生成 DjangoQ对象的核心逻辑、REST API 调用方式、前端实时匹配matches机制以及两端注册流程的源码级细节帮助你在 Baserow 插件中安全地扩展数据筛选能力。1. 核心概念过滤器类型是什么为什么需要双端实现一个视图过滤器由三部分组成字段field、类型type、值value。过滤器实例存储在后端ViewFilter模型中可以在 视图模型定义 中看到ViewFilterGroup与ViewFilter两个模型——它们支持分组filter group语义用于构建 AND/OR 复合过滤条件。过滤器类型本身是两端各一份代码的后端负责在数据库查询时把过滤器编译成 DjangoQ对象并应用到 queryset保证 API 返回的行是真正经过过滤的前端负责在用户选择字段时展示可用的过滤器类型、渲染值输入组件并在行数据被编辑后实时判断该行是否仍满足当前过滤器。正如 官方教程 所述前端需要一份同样的过滤逻辑是因为当用户编辑某一行后系统要立即判断该行是否还匹配视图当前过滤器如果不匹配就会向用户显示警告——若保存编辑该行将被从视图中过滤掉。这种实时比较不能等待服务器往返因此过滤逻辑必须在前后端各实现一次。本文将以一个最简单的equal_to相等过滤器为例该功能 Baserow 已内置选它纯粹因为逻辑简单完整走一遍插件开发流程。开发插件的目录结构建议参考 插件样板说明 与 插件入门。2. 后端实现 ViewFilterType 并返回 Django Q 对象2.1 后端抽象类的真实定义所有后端过滤器类型都必须继承ViewFilterType抽象类它定义在 backend/src/baserow/contrib/database/views/registries.py。其核心契约如下type过滤器类型的唯一标识字符串前后端必须一致例如equal_tocompatible_field_types声明该过滤器兼容哪些字段类型。列表中既可以写字面量字段类型名text也可以写接收具体Field实例并返回布尔值的 callable用于表达更细粒度的兼容规则例如只兼容开启某属性的字段get_filter(self, field_name, value, model_field, field)必须重写。它接收字段名、过滤值、Django 模型字段model_field与 BaserowField实例field需要返回一个Q对象或OptionallyAnnotatedQ见 field_filters.py。返回的Q对象会被框架自动合并进视图的 queryset。两个容易忽视的默认行为值得注意值不兼容时的兜底策略基类提供了default_filter_on_exception()方法默认返回Q(pk__in[])registries.py即当过滤值类型与字段不兼容时默认不返回任何行。你可以在子类中重写它来改变这一策略例如返回Q()表示不过滤字段兼容性的解析链路field_is_compatible(field)在检查时会先调用字段类型的get_compatible_filter_field_type(field)做“类型别名”解析——某些字段类型如公式字段可以把自己映射为另一种类型参与兼容性判断registries.py。这就是为什么内置的公式字段也能被普通文本过滤器使用。2.2 完整示例equal_to 过滤器创建一个EqualToViewFilterType声明它只兼容text字段# plugins/my_baserow_plugin/backend/src/my_baserow_plugin/view_filters.py from django.db.models import Q from baserow.contrib.database.views.registries import ViewFilterType class EqualToViewFilterType(ViewFilterType): type equal_to compatible_field_types [text] def get_filter(self, field_name, value, model_field, field): value value.strip() # 如果提供了空值我们不做任何过滤。 if value : return Q() # 检查 model_field 是否能接受该值。 try: value model_field.get_prep_value(value) return Q(**{field_name: value}) except Exception: pass return Q()get_filter的三个关键分支值得逐个理解分支代码含义空值if value : return Q()空的Q()对象与任何条件组合都不产生约束因此“未填写过滤值 不过滤”是 Baserow 过滤器的通用约定值可转换model_field.get_prep_value(value)后Q(**{field_name: value})get_prep_value是 Django 模型字段的入口负责把字符串值转换成数据库可比较的形式如数值、日期解析成功后用Q(**{field_name: value})生成等值比较值不可转换except Exception: return Q()当值无法被目标字段接受时例如给数值字段填了非法文本示例选择退化为“不过滤”从而避免 500 错误2.3 注册到注册表最后一步是在插件的AppConfig.ready()中把过滤器类型注册进view_filter_type_registry。该注册表的name为view_filter重复注册会抛出ViewFilterTypeAlreadyRegistered未注册的类型查询会抛出ViewFilterTypeDoesNotExistregistries.py# plugins/my_baserow_plugin/backend/src/my_baserow_plugin/config.py from django.apps import AppConfig from baserow.core.registries import plugin_registry from baserow.contrib.database.views.registries import view_filter_type_registry class PluginNameConfig(AppConfig): name my_baserow_plugin def ready(self): from .plugins import PluginNamePlugin from .view_filters import EqualToViewFilterType plugin_registry.register(PluginNamePlugin()) view_filter_type_registry.register(EqualToViewFilterType())2.4 值得重写的进阶钩子除了get_filter基类还预留了若干可选方法registries.py在编写复杂过滤器时可以直接利用get_preload_values(view_filter)为展示目的预加载附加数据。内置的link_row_has过滤器就用它预取所选行的名称供 API 序列化时展示get_export_serialized_value(value, id_mapping)/set_import_serialized_value(value, id_mapping)当过滤值引用了内部 ID如 select 选项、行 ID时在视图导出/导入模板、复制表过程中负责值的转换与 ID 重映射。视图的export_serialized流程会逐个过滤器调用前者registries.pytime_sensitive声明过滤结果是否依赖当前时间例如 “today”“yesterday” 这类日期操作符注册表会据此汇总时间敏感过滤器列表供前端决定何时重新计算过滤结果。3. 通过 REST API 使用新过滤器后端过滤器类型创建后即可通过 API 为某个视图需先存在一个包含相应字段的 grid 视图添加过滤器实例POST /api/database/views/{view_id}/filters/ Host: api.baserow.io Content-Type: application/json { field: {field_id}, type: equal_to, value: Example }等价 curl 命令curl -X POST -H Content-Type: application/json -i \ https://api.baserow.io/api/database/views/{view_id}/filters/ \ --data { field: {field_id}, type: equal_to, value: Example }请求体三个字段与ViewFilter模型一一对应field指向被过滤的字段 IDtype必须是已注册的过滤器类型标识value是过滤值按字符串存储由get_filter负责解释。过滤器创建后刷新网格视图的列表接口即可只看到满足条件的行GET /api/database/views/grid/{view_id}/ Host: api.baserow.io Content-Type: application/jsoncurl -X GET -H Content-Type: application/json -i \ https://api.baserow.io/api/database/views/grid/{view_id}/4. 前端实现并注册 ViewFilterType后端只负责“算得对”前端负责“选得出、看得到、实时比对”。前端基类ViewFilterType定义在 web-frontend/modules/database/viewFilters.js构造函数会基于getType()静态方法生成type并在类型或名称缺失时直接抛错viewFilters.js。子类需要实现的方法方法职责基类默认行为static getType()过滤器类型标识必须与后端type一致无必须实现getName()用户在下拉菜单中看到的显示名称返回null构造函数会因此报错getInputComponent(field)返回处理过滤值输入的 Vue 组件须遵循 v-model 原则可按字段类型返回不同组件返回null即不显示任何输入框getCompatibleFieldTypes()返回兼容的字段类型名列表也可混合传入接收 field 的函数谓词返回[]即不兼容任何字段matches(rowValue, filterValue, field, fieldType)判断行的值是否满足过滤值用于实时比对抛出异常必须实现4.1 示例实现// plugins/my_baserow_plugin/web-frontend/viewTypes.js import { ViewFilterType } from baserow/modules/database/viewFilters import ViewFilterTypeText from baserow/modules/database/components/view/ViewFilterTypeText export class EqualViewFilterType extends ViewFilterType { static getType() { return equal_to } getName() { return is 2 } getInputComponent() { // 处理值输入的组件这里复用现有的文本输入组件 // 也可以自定义组件组件需遵循 v-model 原则。 return ViewFilterTypeText } getCompatibleFieldTypes() { return [text] } matches(rowValue, filterValue) { if (rowValue null) { rowValue } rowValue rowValue.toString().toLowerCase().trim() filterValue filterValue.toString().toLowerCase().trim() return filterValue || rowValue filterValue } }注意matches中filterValue 返回true的写法它与后端Q()“空值不过滤”的语义保持一致——过滤值未填时任何行都算“匹配”这样用户编辑行时不会因为过滤器值为空而误触发“将被过滤”警告。基类还提供了一批可直接复用的行为viewFilters.jsserialize()会把type、name、compatibleFieldTypes序列化出去供 UI 使用getDefaultValue(field)决定新建过滤器时的默认值时区敏感过滤器可在此返回当前时区prepareValue(value, field)在值提交前做转换比如把日期选择器值拼成时区\0值\0操作符的三段式字符串isAllowedInPublicViews()与isDeprecated()分别控制过滤器在公共视图中是否可用、是否从下拉框中隐藏已废弃类型仍可用于既有过滤器。内置实现中的fieldIsCompatible(field)与getCompatibleFieldValue(field, valuesMap, notFoundValue)两个方法体现了“类型别名”机制的前端对应物它们先通过字段类型的getCompatibleFilterFieldType(field)解析出规范类型再比对兼容列表viewFilters.js与后端field_is_compatible的get_compatible_filter_field_type链路对称——这正是第 2.1 节提到的公式字段能够被文本类过滤器使用的底层原因。对于需要按字段类型切换输入组件与值解析逻辑的场景仓库提供了一个中间基类SpecificFieldFilterTypeviewFilters.js它维护一张“字段类型 → 具体处理器如NumberFieldViewFilterHandler、TextLikeFieldViewFilterHandler”的映射getInputComponent与值解析parseRowValue/parseFilterValue都委托给对应处理器。内置的EqualViewFilterType就继承自它viewFilters.js你的插件若要对多种字段类型做不同解析可以参照这一模式。4.2 前端注册与 field type 教程 中的注册方式一致前端通过app.$registry.register(viewFilter, ...)注册过滤器。内置过滤器就是在 web-frontend/modules/database/plugin.js 中这样注册的先执行registerNamespace(viewFilter)再逐个register// plugins/my_baserow_plugin/web-frontend/plugin.js import { PluginNamePlugin } from my-baserow-plugin/plugins import { EqualViewFilterType } from my-baserow-plugin/viewFilters export default (context) { const { app } context app.$registry.register(plugin, new PluginNamePlugin(context)) app.$registry.register(viewFilter, new EqualViewFilterType(context)) }5. 验证与检查清单完成上述代码后在视图中为某个 text 字段添加过滤器应该能在过滤器类型下拉菜单中看到显示名称示例中的is 2并能输入文本值与字段值比较。可以按以下清单核对实现是否完整两端 type 一致后端EqualToViewFilterType.type与前端EqualViewFilterType.getType()都返回equal_to两端兼容列表一致后端的compatible_field_types与前端的getCompatibleFieldTypes()都声明了[text]否则会出现“前端可选、后端拒绝”或反向的错位matches与get_filter语义一致后端空值返回Q()不过滤前端空值返回true全部匹配两者对同一数据集的判定结果应当一致注册无冲突重复注册会触发ViewFilterTypeAlreadyRegistered异常开发时注意插件热重载值的可移植性若过滤值引用了内部 ID选项、行记得实现get_export_serialized_value/set_import_serialized_value钩子保证模板与复制导出的正确性。6. 小结自定义视图过滤器类型的开发路径可以概括为后端继承ViewFilterType→ 实现get_filter返回Q→ 注册进view_filter_type_registry→ 前端继承同名ViewFilterType→ 实现getName/getInputComponent/getCompatibleFieldTypes/matches→ 通过register(viewFilter)注册。后端保证 API 数据层面的正确过滤registries.py前端保证交互展示与行编辑后的实时匹配警告viewFilters.js两者缺一不可。理解了compatible_field_types的 callable 扩展位、get_export_serialized_value等钩子以及前后端对称的“字段类型别名”机制之后你就可以在 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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价