You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 07:57:27