Odoo实现手动输入错误日期时弹出警告的方法
Odoo全局日期字段非法输入校验实现方案
要实现全系统所有日期字段(含官方默认模块字段)的非法输入拦截,阻止默认的错误输入清空、旧值回退存库逻辑,需要做前端组件拦截+后端全局校验双层实现,覆盖所有手动输入非法日期的场景。
核心逻辑说明
Odoo默认行为是:手动输入的日期字符串无法被日期组件解析时,会直接丢弃输入值,回退到该字段之前存储的有效值,无任何提示直接存库。我们需要修改日期基础组件的解析逻辑,保留用户的错误输入,在保存环节拦截并弹出警告,同时加后端兜底校验避免前端绕过。
具体实现步骤
新建一个自定义的全局模块,目录结构如下:
date_global_validation/ ├── __init__.py ├── __manifest__.py └── models/ ├── __init__.py └── base_date_validate.py └── static/ └── src/ └── js/ └── date_field_patch.js
1. 模块配置文件编写
首先编写模块清单文件__manifest__.py,声明对web核心模块的依赖,加载前端补丁文件:
{ 'name': 'Global Date Validation', 'version': '16.0.1.0.0', # 可根据自身使用的Odoo版本调整,15/16/17版本逻辑通用 'depends': ['web'], 'assets': { 'web.assets_backend': [ 'date_global_validation/static/src/js/date_field_patch.js', ], }, 'installable': True, 'application': False, 'auto_install': True, # 设为自动安装,启用后无需手动逐个模块适配 }
根目录__init__.py内容:
from . import models
models目录下__init__.py内容:
from . import base_date_validate
2. 前端组件补丁编写
编辑static/src/js/date_field_patch.js,给系统通用的DateField、DateTimeField基础组件打补丁,所有继承这两个基础类的日期字段(全系统所有日期字段)都会继承该校验逻辑:
/** @odoo-module **/ import { DateField, DateTimeField } from "@web/views/fields/date/date_field"; import { patch } from "@web/core/utils/patch"; import { _t } from "@web/core/l10n/translation"; const commonDatePatch = { setup() { this._super(...arguments); this.isInvalidDate = false; }, parseValue(rawValue) { const parsedResult = this._super(...arguments); // 输入非空但解析失败时,标记非法状态,保留原始输入不回退旧值 if (rawValue && !parsedResult) { this.isInvalidDate = true; return rawValue; } this.isInvalidDate = false; return parsedResult; }, async updateRecord() { // 记录更新/保存前校验非法状态,拦截保存流程弹出警告 if (this.isInvalidDate) { this.notification.add( _t("please enter correct date"), { type: "warning", sticky: false } ); return Promise.reject(); } return this._super(...arguments); } }; // 同时给普通日期、日期时间类型字段打补丁 patch(DateField.prototype, commonDatePatch); patch(DateTimeField.prototype, commonDatePatch);
3. 后端全局兜底校验编写
编辑models/base_date_validate.py,给所有模型的create、write方法加全局日期校验,防止前端逻辑被绕过(如API调用、其他端录入)导致非法值入库:
import re from odoo import api, models, _ from odoo.exceptions import ValidationError from datetime import datetime class BaseModelGlobalDateValidate(models.AbstractModel): _inherit = 'base' @api.model_create_multi def create(self, vals_list) { self._check_date_value_valid(vals_list) return super().create(vals_list) } def write(self, vals) { self._check_date_value_valid([vals]) return super().write(vals) } def _check_date_value_valid(self, vals_list) { // 收集当前模型下所有日期、日期时间字段 date_fields = [] datetime_fields = [] for fname, field in self._fields.items(): if field.type == 'date': date_fields.append(fname) elif field.type == 'datetime': datetime_fields.append(fname) date_format_re = re.compile(r'^\d{4}-\d{2}-\d{2}$') datetime_format_re = re.compile(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$') for vals in vals_list: for k, v in vals.items(): if not v or not isinstance(v, str): continue // 校验date类型字段 if k in date_fields: try: if not date_format_re.match(v): raise ValueError() datetime.strptime(v, '%Y-%m-%d') except ValueError: raise ValidationError(_("please enter correct date")) // 校验datetime类型字段 if k in datetime_fields: try: if not datetime_format_re.match(v): raise ValueError() datetime.strptime(v, '%Y-%m-%d %H:%M:%S') except ValueError: raise ValidationError(_("please enter correct date")) } }
效果验证
模块安装完成后,全系统所有日期、日期时间字段,手动输入35/13/2022、32/13/2022这类不存在的非法日期时:
- 不会自动清空输入内容、回退到之前存储的旧值
- 点击保存时会直接弹出
please enter correct date的警告提示 - 日期选择器的正常选值逻辑完全不受影响
- 即使绕过前端直接传参调用接口,后端也会拦截非法日期值并抛出相同警告
适配说明
- 如果你的系统自定义了日期显示格式(如
dd/mm/yyyy、mm/dd/yyyy),只需要对应调整前端日期解析的判定规则即可,核心拦截逻辑不变 - Odoo14及更低版本需要调整前端组件的导入路径(旧版日期组件定义在
web.form_widgets模块下),后端校验逻辑可直接复用
内容的提问来源于stack exchange,提问作者Gautam Bothra
相关产品推荐
相关产品推荐

