odoo19-syntax

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Odoo 19 Syntax Skill

Odoo 19语法技能

This skill ensures generated code matches Odoo 19 (released September 2025) syntax conventions, NOT older versions. Odoo 19 introduces ~130 model renames, the largest schema change since Odoo 14, plus continued enforcement of changes from Odoo 17/18.
本技能确保生成的代码符合Odoo 19(2025年9月发布)的语法规范,而非旧版本。Odoo 19引入了约130个模型重命名,这是自Odoo 14以来最大的架构变更,同时持续推行Odoo 17/18中的变更。

CRITICAL: Detect the version FIRST

关键:先检测版本

This skill applies ONLY to Odoo 19 projects. Before suggesting any syntax, determine the project's Odoo version. If the project is NOT Odoo 19, stop using this skill and let the user know — do not silently apply Odoo 19 syntax to an Odoo 17/18 codebase, because it will break.
Detection priority (try in order, stop at the first that works):
本技能仅适用于Odoo 19项目。 在建议任何语法之前,请确定项目的Odoo版本。如果项目不是Odoo 19,请停止使用本技能并告知用户——不要将Odoo 19语法静默应用到Odoo 17/18代码库中,否则会导致代码崩溃。
检测优先级(按顺序尝试,找到有效结果后停止):

1. Read
__manifest__.py
of the target module

1. 读取目标模块的
__manifest__.py

Look for the
version
field. The first two numbers indicate the Odoo version:
python
{
    'name': 'My Module',
    'version': '19.0.1.0.0',   # ← Odoo 19
    # ...
}
  • '19.0.x.x.x'
    → Odoo 19, this skill applies.
  • '18.0.x.x.x'
    ,
    '17.0.x.x.x'
    , etc. → Different version, STOP and skip this skill.
  • Missing version field → Continue to step 2.
If multiple
__manifest__.py
files exist, read the one for the module being edited. If unsure which module, check the file path of the user's request (e.g.,
addons/sale_custom/models/...
→ read
addons/sale_custom/__manifest__.py
).
查找
version
字段。前两位数字表示Odoo版本:
python
{
    'name': 'My Module',
    'version': '19.0.1.0.0',   # ← Odoo 19
    # ...
}
  • '19.0.x.x.x'
    → Odoo 19,适用本技能。
  • '18.0.x.x.x'
    '17.0.x.x.x'
    等 → 其他版本,停止并跳过本技能
  • 缺少version字段 → 继续步骤2。
如果存在多个
__manifest__.py
文件,请读取正在编辑的模块对应的文件。如果不确定是哪个模块,请检查用户请求的文件路径(例如:
addons/sale_custom/models/...
→ 读取
addons/sale_custom/__manifest__.py
)。

2. Read Odoo source
release.py

2. 读取Odoo源码的
release.py

If the project is a full Odoo source checkout, look for
odoo/release.py
or
odoo/__init__.py
containing
version_info
:
python
version_info = (19, 0, 0, 'final', 0, '')
The first integer is the major version.
Common locations to check (use
view
or
bash
find
):
  • ./odoo/release.py
  • ./release.py
  • ./odoo-bin
    followed by source tree
如果项目是完整的Odoo源码检出版本,请查找包含
version_info
odoo/release.py
odoo/__init__.py
python
version_info = (19, 0, 0, 'final', 0, '')
第一个整数是主版本号。
常见检查位置(使用
view
或bash的
find
命令):
  • ./odoo/release.py
  • ./release.py
  • ./odoo-bin
    及后续源码树

3. Check
requirements.txt
,
pyproject.toml
, or Docker config

3. 检查
requirements.txt
pyproject.toml
或Docker配置

Sometimes the version is pinned via:
  • A line like
    odoo==19.0.*
    in
    requirements.txt
  • An image like
    odoo:19.0
    in
    docker-compose.yml
    or
    Dockerfile
有时版本会通过以下方式固定:
  • requirements.txt
    中的
    odoo==19.0.*
  • docker-compose.yml
    Dockerfile
    中的
    odoo:19.0
    镜像

4. Ask the user

4. 询问用户

If steps 1–3 fail, ask the user directly: "I couldn't auto-detect the Odoo version from the project files. Which version is this — Odoo 19, or something else?" Do not assume Odoo 19 by default.
如果步骤1-3失败,请直接询问用户:“我无法从项目文件中自动检测Odoo版本。这是哪个版本——Odoo 19还是其他版本?”不要默认假设是Odoo 19。

Behavior when version ≠ 19

版本≠19时的处理

If detection shows the project is Odoo 17, 18, or earlier:
  1. Tell the user: "This project appears to be on Odoo X.0, not Odoo 19. I'll skip the Odoo 19 syntax skill and write code matching Odoo X.0 conventions instead."
  2. Do NOT load the references in this skill for code generation.
  3. Use your general Odoo knowledge for that version.
If the project is Odoo 19 (or version is uncertain and the user confirmed 19), proceed with the rest of this skill.

如果检测到项目是Odoo 17、18或更早版本:
  1. 告知用户:“该项目似乎使用的是Odoo X.0版本,而非Odoo 19。我将跳过Odoo 19语法技能,编写符合Odoo X.0规范的代码。”
  2. 代码生成时不要加载本技能中的参考内容。
  3. 使用你对该版本Odoo的通用知识。
如果项目是Odoo 19(或版本不确定但用户确认是19),请继续使用本技能的剩余内容。

How to use this skill (once Odoo 19 is confirmed)

如何使用本技能(确认是Odoo 19后)

The detailed syntax rules are split into reference files by domain. Load only the references relevant to the current task — you don't need all of them every time.
Task involves...Load this reference
Python models, ORM, fields, methods, constraints
references/orm.md
XML views (form, list/tree, kanban, search), QWeb
references/views.md
HTTP controllers, routes, RPC endpoints
references/controllers.md
OWL components, services, JS in
static/src/
references/owl_js.md
__manifest__.py
, hooks, security, asset bundles
references/manifest_security.md
SCSS files, asset registration
references/scss_assets.md
Model name lookups (hr.contract? procurement.group?)
references/model_renames.md
Always load
references/orm.md
and
references/views.md
for any non-trivial Python+XML task
— they're the most frequent source of mistakes.
For model name questions (e.g., "is the model still
hr.contract
?"),
references/model_renames.md
is the source of truth — Odoo 19 renamed 130 models.
详细的语法规则按领域拆分到参考文件中。仅加载与当前任务相关的参考内容——不需要每次都加载所有内容。
任务涉及...加载此参考
Python模型、ORM、字段、方法、约束
references/orm.md
XML视图(表单、列表/tree、看板、搜索)、QWeb
references/views.md
HTTP控制器、路由、RPC端点
references/controllers.md
OWL组件、服务、
static/src/
中的JS
references/owl_js.md
__manifest__.py
、钩子、安全、资源包
references/manifest_security.md
SCSS文件、资源注册
references/scss_assets.md
模型名称查询(hr.contract?procurement.group?)
references/model_renames.md
对于任何非简单的Python+XML任务,请务必加载
references/orm.md
references/views.md
——它们是最常见错误的来源。
对于模型名称问题(例如:“模型还是
hr.contract
吗?”),
references/model_renames.md
是权威来源——Odoo 19重命名了130个模型。

Workflow for a code-generation request

代码生成请求的工作流程

  1. Detect version (per the section above). If not Odoo 19, exit this skill.
  2. Identify the task domain(s) — Python? Views? OWL? Controllers? Multiple?
  3. Load relevant references — read each
    references/*.md
    file you need.
  4. For any model name the user mentions or you plan to use, cross-check
    references/model_renames.md
    . Do not skip this — model renames are the silent-failure category.
  5. Generate code following the patterns in the references.
  6. Self-check before responding: scan your draft for these red flags:
    Constraints, decorators, imports:
    • _sql_constraints = [...]
      → should be
      _constraints = [models.Constraint(...)]
      in Odoo 19
    • from odoo.models import Constraint
      → unnecessary; use
      models.Constraint(...)
      directly
    • from odoo.fields import Command
      → must be
      from odoo import Command
    • from odoo.osv.expression import OR/AND
      → use
      Domain.OR
      /
      Domain.AND
      (
      from odoo import Domain
      )
    • @api.returns(...)
      decorator → REMOVED in Odoo 19, drop it
    • Helper method exposed via RPC by accident → consider
      @api.private
    Record/env access:
    • self._cr
      self.env.cr
    • self._context
      self.env.context
    • self._uid
      self.env.uid
    • self._context.get('tz')
      self.env.tz
    • self._context.get('allowed_company_ids')
      self.env.companies
    Methods:
    • name_get(self)
      → must be
      _compute_display_name(self)
    • read_group(...)
      _read_group(...)
      (backend) or
      formatted_read_group(...)
    • check_access_rights(...)
      /
      check_access_rule(...)
      check_access(...)
      (combined)
    • _render_qweb_pdf(...)
      → must be
      _render(...)
    • SavepointCase
      import → must be
      TransactionCase
    • (0, 0, {...})
      tuple syntax for O2M/M2M → use
      Command.create({...})
    Domain syntax:
    • Uppercase domain operators (
      'LIKE'
      ,
      'IN'
      , etc.) → must be lowercase
    • Complex relational subqueries via dot-notation → consider
      ('field_ids', 'any', [...])
      operator
    Views (XML):
    • attrs="{...}"
      → must be inline
      invisible=
      ,
      readonly=
      ,
      required=
    • <tree>
      → must be
      <list>
    • <group string="..."
      or
      <group expand="..."
      inside
      <search>
      view → drop both, leave
      <group>
      bare
    • t-raw="..."
      → must be
      t-out="..."
    • t-esc="..."
      → REMOVED in Odoo 19, must be
      t-out="..."
    • <chatter>
      boilerplate (3 fields) → use
      <chatter/>
      shorthand
    • <t t-call>
      with nested
      <t t-set>
      → use attribute syntax
      <t t-call="tpl" var="value"/>
    Manifest, hooks, config:
    • post_init_hook(cr, registry)
      signature → must be
      post_init_hook(env)
    • Manifest missing
      'license'
      key → required (e.g.
      'LGPL-3'
      )
    • xmlrpc_port
      in odoo.conf →
      http_port
    Controllers:
    • type="json"
      on a route called by the web client → likely should be
      type="jsonrpc"
    SCSS:
    • SCSS using
      /
      for division → must use
      math.div(...)
      or
      calc(...)
    • SCSS
      @import "..."
      → must use
      @use "..."
      (dart-sass)
    Renamed models (silent failures — see
    model_renames.md
    ):
    • hr.contract
      hr.version
    • procurement.group
      stock.reference
    • stock.quant.package
      stock.package
    • bus.presence
      mail.presence
    • hr.candidate
      hr.applicant
    • hr.employee.base
      → REMOVED (use
      hr.employee
      )
    • res.partner.title
      → REMOVED
    • stock.valuation.layer
      → REMOVED (data on
      stock.move
      )
    • hr.expense.sheet
      → REMOVED
    Renamed fields:
    • groups_id
      group_ids
      (on
      res.users
      , menus, views, actions, rules)
    • tax_id
      tax_ids
      on
      sale.order.line
      ;
      taxes_id
      tax_ids
      on
      purchase.order.line
    • product_uom
      product_uom_id
      on sale/purchase lines
    • purchase.order.notes
      note
    • fleet.vehicle.first_contract_date
      contract_date_start
    Removed fields (delete from code/XML):
    • <field name="numbercall">
      on
      ir.cron
      records
    • res.partner.mobile
      (use
      phone
      ),
      res.partner.title
      ,
      res.partner.picking_warn
      ,
      res.partner.last_website_so_id
    • account.move.line.product_uom_category_id
      ,
      product.uom.category_id
    • product.template.sale_line_warn
    OWL/JS specific:
    • this.pos.get_order()
      this.pos.getOrder()
      (camelCase)
    • request.website.sale_get_order()
      request.cart
    • request.website.pricelist_id
      request.pricelist
If any red flag fires, fix the code before showing it to the user.
  1. 检测版本(按照上述章节)。如果不是Odoo 19,退出本技能。
  2. 确定任务领域——Python?视图?OWL?控制器?多个领域?
  3. 加载相关参考内容——读取所需的每个
    references/*.md
    文件。
  4. 对于用户提及或你计划使用的任何模型名称,交叉检查
    references/model_renames.md
    。不要跳过这一步——模型重命名是会导致静默失败的类别。
  5. 生成代码——遵循参考内容中的模式。
  6. 回复前自我检查:扫描草稿中的以下危险信号:
    约束、装饰器、导入:
    • _sql_constraints = [...]
      → Odoo 19中应改为
      _constraints = [models.Constraint(...)]
    • from odoo.models import Constraint
      → 不必要;直接使用
      models.Constraint(...)
    • from odoo.fields import Command
      → 必须改为
      from odoo import Command
    • from odoo.osv.expression import OR/AND
      → 使用
      Domain.OR
      /
      Domain.AND
      (需
      from odoo import Domain
    • @api.returns(...)
      装饰器 → Odoo 19中已移除,请删除
    • 意外通过RPC暴露的辅助方法 → 考虑使用
      @api.private
    记录/环境访问:
    • self._cr
      self.env.cr
    • self._context
      self.env.context
    • self._uid
      self.env.uid
    • self._context.get('tz')
      self.env.tz
    • self._context.get('allowed_company_ids')
      self.env.companies
    方法:
    • name_get(self)
      → 必须改为
      _compute_display_name(self)
    • read_group(...)
      _read_group(...)
      (后端)或
      formatted_read_group(...)
    • check_access_rights(...)
      /
      check_access_rule(...)
      check_access(...)
      (合并后的方法)
    • _render_qweb_pdf(...)
      → 必须改为
      _render(...)
    • SavepointCase
      导入 → 必须改为
      TransactionCase
    • O2M/M2M的
      (0, 0, {...})
      元组语法 → 使用
      Command.create({...})
    域语法:
    • 大写的域操作符(
      'LIKE'
      'IN'
      等) → 必须改为小写
    • 通过点符号实现的复杂关系子查询 → 考虑使用
      ('field_ids', 'any', [...])
      操作符
    视图(XML):
    • attrs="{...}"
      → 必须改为内联的
      invisible=
      readonly=
      required=
    • <tree>
      → 必须改为
      <list>
    • <search>
      视图中的
      <group string="..."
      <group expand="..."
      → 删除这两个属性,保留
      <group>
      即可
    • t-raw="..."
      → 必须改为
      t-out="..."
    • t-esc="..."
      → Odoo 19中已移除,必须改为
      t-out="..."
    • <chatter>
      模板代码(3个字段) → 使用
      <chatter/>
      简写形式
    • 嵌套
      <t t-set>
      <t t-call>
      → 使用属性语法
      <t t-call="tpl" var="value"/>
    清单、钩子、配置:
    • post_init_hook(cr, registry)
      签名 → 必须改为
      post_init_hook(env)
    • 清单文件缺少
      'license'
      键 → 必填(例如
      'LGPL-3'
    • odoo.conf中的
      xmlrpc_port
      → 改为
      http_port
    控制器:
    • 被Web客户端调用的路由上的
      type="json"
      → 应改为
      type="jsonrpc"
    SCSS:
    • 使用
      /
      进行除法的SCSS → 必须使用
      math.div(...)
      calc(...)
    • SCSS的
      @import "..."
      → 必须使用
      @use "..."
      (dart-sass)
    重命名的模型(静默失败——见
    model_renames.md
    ):
    • hr.contract
      hr.version
    • procurement.group
      stock.reference
    • stock.quant.package
      stock.package
    • bus.presence
      mail.presence
    • hr.candidate
      hr.applicant
    • hr.employee.base
      → 已移除(使用
      hr.employee
    • res.partner.title
      → 已移除
    • stock.valuation.layer
      → 已移除(数据在
      stock.move
      上)
    • hr.expense.sheet
      → 已移除
    重命名的字段:
    • groups_id
      group_ids
      (在
      res.users
      、菜单、视图、动作、规则上)
    • sale.order.line
      上的
      tax_id
      tax_ids
      purchase.order.line
      上的
      taxes_id
      tax_ids
    • 销售/采购行上的
      product_uom
      product_uom_id
    • purchase.order.notes
      note
    • fleet.vehicle.first_contract_date
      contract_date_start
    已移除的字段(从代码/XML中删除):
    • ir.cron
      记录上的
      <field name="numbercall">
    • res.partner.mobile
      (使用
      phone
      )、
      res.partner.title
      res.partner.picking_warn
      res.partner.last_website_so_id
    • account.move.line.product_uom_category_id
      product.uom.category_id
    • product.template.sale_line_warn
    OWL/JS特定:
    • this.pos.get_order()
      this.pos.getOrder()
      (驼峰命名)
    • request.website.sale_get_order()
      request.cart
    • request.website.pricelist_id
      request.pricelist
如果检测到任何危险信号,请在展示给用户前修复代码。

What NOT to do

禁止事项

  • Do not apply Odoo 19 conventions to projects on older versions.
  • Do not skip the version-check step "because the user said Odoo 19" — verify by reading at least one project file when possible.
  • Do not assume
    _sql_constraints
    is wrong without confirming Odoo 19; it still works in 18 and earlier.
  • Do not tell the user "this is the Odoo way" without specifying the version — say "in Odoo 19, ..." explicitly.
  • 不要将Odoo 19规范应用到旧版本项目中。
  • 不要因为“用户说过是Odoo 19”就跳过版本检查步骤——尽可能通过读取至少一个项目文件进行验证。
  • 不要在未确认是Odoo 19的情况下就认为
    _sql_constraints
    是错误的;它在18及更早版本中仍然有效。
  • 不要不指定版本就告诉用户“这是Odoo的方式”——明确说明“在Odoo 19中,……”。