Odoo14开发者指南第六章-管理模块数据【翻译】

在本章中,我们将了解如何在安装附加模块时提供数据。在提供默认值、添加元数据(例如视图描述、菜单或操作)时对我们很有用。另一个重要的用途是提供演示数据,选中加载演示数据 复选框后,在创建数据库时加载演示数据。

在本章中,我们将介绍以下内容:

技术要求

本章的技术要求包括在线的Odoo平台。

本章中使用的所有代码都可以从以下GitHub存储库下载:

https://github.com/PacktPublishing/Odoo-14-Development-Cookbook-Fourth-Edition/tree/master/Chapter06

为了避免重复大量代码,我们将使用第四章《应用模型》中定义的模型。要遵循这些示例,请确保从Chapter04/r6_hierarchy_model/my_library 获取my_library 模块的代码。

使用外部ID和命名空间

Odoo中的外部ID或XML ID用于识别记录。到目前为止,在本书中,我们已经在视图、菜单和操作等领域使用了XML ID。但是,我们还没有看到XML ID的真正含义。本节会让你有更深入的了解。

实现步骤

我们将写入已经存在的记录来演示如何使用跨模块引用:

  1. 更新my_library 模块的清单文件注册数据文件:

    1
    2
    3
    'data': [
    'data/data.xml',
    ],
  2. library.book 模型中创建一本新书:

    1
    2
    3
    <record id="book_cookbook" model="library.book">
    <field name="name"> Odoo 14 Development Cookbook </field>
    </record>
  3. 更改主公司名称:

    1
    2
    3
    <record id="base.main_company" model="res.company">
    <field name="name">Packt publishing</field>
    </record>

安装模块以应用更改。安装后将创建新的书籍记录Odoo 14 Development Cookbook ,公司将更名为Packt publishing

运行原理

XML ID是引用数据库中记录的字符串。ID本身是ir.model.data 模型的记录。该模型包含声明XML ID的模块名称、ID字符串、引用模型和引用ID等数据。

每次我们在<record> 标签上使用XML ID时,Odoo都会检查字符串是否已命名空间(即它是否正好包含一个点),如果没有,它会将使用当前模块名称作为命名空间。 然后,它会查找ir.model.data 中是否已经存在具有指定名称的记录。如果存在,则执行列出字段的UPDATE 语句; 如果不存在,则执行CREATE 语句。这是在记录已经存在时提供部分数据的方式,就像我们之前所做的那样。

在章的第一个示例中,记录的ID为book_cookbook 。由于它还没有命名,因此最终的外部ID将具有这样的模块名称:my_library.book_cookbook 。然后Odoo将尝试查找my_library.book_cookbook 的记录。 由于Odoo还没有该外部ID的记录,它将在library.book 模型中生成新记录。

在第二个示例中,我们使用了主公司的外部ID,即base.main_company。正如其命名空间所暗示的,它是从基本模块加载的。由于外部ID已经存在,而不是创建记录,Odoo将执行write(UPDATE) 操作更新公司名为Packt publishing

重要笔记
除了更改其他模块定义的记录外,部分数据的广泛应用是使用快捷方式元素以方便的方式创建记录并在该记录上写入字段,快捷方式元素不支持:

1
2
3
4
<act_window id="my_action" name="My action" model="res.partner" />
<record id="my_action" model="ir.actions.act_window">
<field name="auto_search" eval="False"/>
</record>

在本章的使用XML文件加载数据一节中使用的ref 函数也会在适当的情况下将当前模块添加为命名空间,但如果生成的XML ID不存在,则会引发错误。如果它还没有命名空间,这也适用于id属性。

提示
如果您想查看所有外部标识符的列表,请激活开发者模式并打开菜单到Settings | Technical | Sequence & Identifiers | External
Identifiers

扩展内容

您可能迟早需要通过Python代码访问具有XML ID的记录。在这些情况下使用self.env.ref() 函数。这将返回被引用记录的浏览记录(记录集)。请注意,在这里,您始终必须传递完整的XML ID。下面是一个完整的XML ID示例:

1
<module_name>.<record_id>

您可以从用户界面查看任何记录的XML ID。为此您需要在Odoo中激活开发者模式。请参阅第一章《安装Odoo开发环境》激活开发者模式。激活开发人员模式后,打开要查找其XML ID的记录的表单视图。您将在顶部栏中看到一个bug图标。从该菜单中,单击View Metadata 选项。请参阅以下屏幕截图以供参考:

打开记录元数据的菜单

也可以看看
请参阅本章的使用noupdate和forcecreate标志章节,了解为什么公司名称仅在模块安装期间更改。

使用XML文件加载数据

在前面的章节中,我们使用外部标识符book_cookbook 创建了新的图书记录。在本节中,我们将从XML文件中添加不同类型的数据。我们将添加一本书和一位作者作为演示数据。我们还将在我们的模块中添加一个知名出版社作为常规数据。

实现步骤

按照给定的步骤创建两个数据XML文件并将它们注册到您的__manifest__.py 文件中:

  1. demo 中将名为data/demo.xml 的文件添加到清单中:

    1
    2
    3
    'demo': [
    'data/demo.xml',
    ],
  2. 将以下内容添加到该文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <odoo>
    <record id="author_pga" model="res.partner">
    <field name="name">Parth Gajjar</field>
    </record>
    <record id="author_af" model="res.partner">
    <field name="name">Alexandre Fayolle</field>
    </record>
    <record id="author_dr" model="res.partner">
    <field name="name">Daniel Reis</field>
    </record>
    <record id="author_hb" model="res.partner">
    <field name="name">Holger Brunn</field>
    </record>
    <record id="book_cookbook" model="library.book">
    <field name="name">Odoo Cookbook</field>
    <field name="short_name">cookbook</field>
    <field name="date_release">2016-03-01</field>
    <field name="author_ids" eval="[(6, 0, [ref('author_af'), ref('author_dr'), ref('author_hb')])]" />
    <field name="publisher_id" ref="res_partner_packt" />
    </record>
    </odoo>
  3. data 部分中将名为data/data.xml 的文件添加到清单中:

    1
    2
    3
    4
    'data': [
    'data/data.xml',
    ...
    ],
  4. 将以下XML内容添加到data/data.xml 文件中:

    1
    2
    3
    4
    5
    6
    7
    <odoo>
    <record id="res_partner_packt" model="res.partner">
    <field name="name">Packt Publishing</field>
    <field name="city">Birmingham</field>
    <field name="country_id" ref="base.uk" />
    </record>
    </odoo>

当你现在更新了你的模块,你会看到我们创建的出版社,如果你的数据库启用了演示数据,如第三章《创建Odoo附加模块》中所指出的,你还会找到这本书及其作者。

运行原理

数据XML文件使用<record> 标签在数据库表中创建一行记录。<record> 标签有两个强制属性,idmodel 。对于id 属性,请参阅使用外部ID和命名空间章节;model 属性是指模型的_name 属性。然后,我们使用<field> 元素填充数据库中的列,由您命名的模型定义。该模型还决定必须填写哪些字段并定义默认值。在这种情况下,您不需要显式地为这些字段赋值。

有两种方法可以在模块清单中注册数据XML文件。一个带有data 键,第二个带有demo 键。每次安装或更新模块时都会加载data 键中的XML文件。仅当您为数据库启用演示数据时,才会加载带有demo 键的XML文件。

在第1步中,我们在清单中使用demo 注册了一个data XML文件。因为我们使用的是demo 键,所以只有在您为数据库启用了演示数据时才会加载XML文件。

在第2步中,在标量值的情况下,<field> 元素可以包含作为简单文本的值。如果您需要传递文件的内容(例如设置图像),请使用<field> 元素上的文件属性并传递相对于附加组件路径的文件名。

对于设置引用有两种方法。 最简单的是使用ref 属性,它适用于many2one 字段,并且只包含要引用的记录的XML ID。对于one2manymany2many 字段,我们需要使用eval 属性。这是一个通用属性,可用于运行Python代码来作为字段的值;例如使用strftime(‘%Y-01-01’) 来填充date 字段。X2many 字段应使用三个元素元组列表来填充,其中元组的第一个值决定要执行的操作。 在eval 属性中,我们可以访问一个名为ref 的函数,该函数返回以字符串传入的XML ID对应的数据库ID。这允许我们在不知道其具体ID的情况下引用记录,这在不同的数据库中可能不同,如下所示:

  • (2, id, False) :这将从数据库中删除带有id 的关联记录。 元组的第三个元素被忽略。

  • (3, id, False) :取消带有id 的记录的从one2many 关联。请注意,此操作不会删除记录,它只是将现有记录保持原样。 元组的最后一个元素也被忽略。

  • (4, id, False) :添加一个记录与id 的记录的关联,并且元组的最后一个元素被忽略。这是最常使用到的,通常会使用ref 函数来获取由其XML ID已知的记录的数据库ID。

  • (5, False, False) :它会切断所有关联,但仍保持所关联的记录的完整性。

  • (6, False, [id,...]) :这会清除当前引用的记录,以将它们替换为ID列表中的记录。元组的第二个元素被忽略。

在第3步和第4步与第1步和第2步相同,仅使用data 键替换了demo 键,这意味着每次安装或升级模块时都会加载XML文件。

重要笔记
请注意,数据文件中的顺序是很重要的,并且数据文件中的记录只能引用列表中较早的数据文件中定义的记录。这就是为什么您应该始终检查您的模块是否安装在空数据库中的原因,因为在开发过程中,您经常会在各处添加记录,这是因为之后定义的记录已经在早期更新的数据库中。
演示数据总是在data 键的文件之后加载,这就是本示例中的引用可生效的原因。

扩展内容

虽然您基本上可以使用记录元素做任何事情,但有一些快捷元素可以让开发人员更方便地创建某些类型的记录。其中包括菜单项、模板和动作窗口。有关这些信息,请参阅第九章《后端视图》和第十四章《CMS网站开发》。

字段元素还可以包含函数元素,它调用模型上定义的函数来提供字段的值。请参阅从XML文件调用函数章节,在该章节里,我们只需调用一个函数直接写入数据库,绕过加载机制。

前面的列表缺少01 的条目,因为它们在加载数据时不是很有用。为了完整起见,它们输入如下:

  • (0, False, {'key': value}) :这将创建引用模型的新记录,其字段从位置3 的字典中填充。元组的第二个元素被忽略。由于这些记录没有XML ID,并且每次更新模块时都会运行,从而导致重复条目,因此最好避免这种情况。相反,在它自己的记录元素中创建记录,并按照本节的工作原理部分中的说明关联它。

  • (1, id, {'key': value}) :这可用于写入已关联的记录。出于我们前面提到的相同原因,您应该在XML文件中避免使用这种语法。

这些语法与我们在第五章《基本服务器端开发》中的创建新记录更新记录集记录的值 中解释的语法相同。

使用noupdate和forcecreate标志

大多数附加模块具有不同类型的数据。有些数据只需要存在模块才能正常工作,其他数据不应该由用户更改,并且大多数数据可以根据用户的需要更改并且只是为了方便而提供。本节将详细说明如何处理不同的类型。首先,我们将在已经存在的记录中写入一个字段,然后我们将创建一个应该在模块更新期间重新创建的记录。

实现步骤

通过在<odoo> 标签或<record> 标签上设置某些属性,我们可以在加载数据时强制执行不同的行为:

  1. 添加将在安装时创建但不会在后续更新中更新的发布者。但是,如果用户删除它,它将被重新创建:

    1
    2
    3
    4
    5
    6
    7
    <odoo noupdate="1">
    <record id="res_partner_packt" model="res.partner">
    <field name="name">Packt publishing</field>
    <field name="city">Birmingham</field>
    <field name="country_id" ref="base.uk"/>
    </record>
    </odoo>
  2. 添加图书类别,它在附加更新期间不会更改,如果用户删除它也不会重新创建:

    1
    2
    3
    4
    5
    <odoo noupdate="1">
    <record id="book_category_all" model="library.book.category" forcecreate="false">
    <field name="name">All books</field>
    </record>
    </odoo>

运行原理

<odoo> 标签可以有一个noupdate 属性,该属性会传递到第一次读取包含的数据记录时创建的ir.model.data 记录,从而最终成为该表中的一列。

Odoo 安装一个插件(称为init 模式)时,所有记录都会被写入,无论noupdateTrue 还是False 。当您更新附加组件(称为update 模式)时,会检查现有XML ID以查看它们是否设置了noupdate 标志,如果是,则忽略尝试写入此XML ID的元素。如果有问题的记录被用户删除,则情况并非如此,这就是为什么您可以通过将记录上的forcecreate 标志设置为false 来强制在更新模式下不重新创建noupdate 记录。

重要笔记
在旧版附加组件(包括8.0和之前的版本)中,您经常会发现一个<openerp> 元素包含一个<data> 元素,该元素包含<record> 和其他元素。这仍然是可能的,但已弃用。现在,<odoo><openerp><data> 具有完全相同的语义; 它们是用来括起XML数据的括号。

扩展内容

如果您想使用noupdate 标志加载记录,您可以使用--init=your_addon-i your_addon 参数运行Odoo服务器。这将迫使Odoo重新加载您的记录。这也将导致重新创建已删除的记录。请注意,如果模块绕过XML ID机制,例如通过在<function> 标签调用的Python代码中创建记录,这可能会导致重复记录和相关的安装错误。

使用此代码,您可以绕过任何noupdate 标志,但首先,请确保这确实是您想要的。解决此处介绍的场景的另一个选项是编写迁移脚本,在附加更新和数据迁移章节中进行详细介绍。

也可看看
Odoo还使用XML ID来跟踪插件更新后要删除的数据。如果记录在更新之前具有来自模块命名空间的XML ID,但在更新期间未恢复XML ID,则该记录及其XML ID将从数据库中删除,因为它们被认为已过时。有关此机制的深入讨论,请参阅附加更新和数据迁移章节。

使用CSV文件加载数据

虽然您可以使用XML文件做任何事情,但当您需要提供大量数据时,这种格式并不是最方便的,尤其是考虑到许多人更愿意在Calc或其他电子表格软件中预处理数据。CSV格式的另一个优点是它是您使用标准导出功能时所得到的。在本节中,我们将看看导入类似表格的数据。

实现步骤

一般情况下access-control listsACLs 请参阅第十章《安全访问》)是一种通过CSV文件加载的数据:

  1. security/ir.model.access.csv 添加到您的清单的data列表中:

    1
    2
    3
    4
    'data': [
    ...
    'security/ir.model.access.csv',
    ],
  2. 在这个文件中为我们的书籍添加一个 ACL(我们已经从第三章《创建Odoo附加模块》添加访问安全 中获得了一些记录):

    1
    2
    id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
    acl_library_book_user,ACL for books,model_library_book,base.group_user,1,0,0,0

至此我们拥有一个ACL允许普通用户阅读书籍记录,但不允许他们编辑、创建或删除它们。

运行原理

您只需将所有数据文件放入清单的data列表中。Odoo将使用文件扩展名来决定它是哪种类型的文件。CSV文件的一个特点是它们的文件名必须与要导入的模型的名称相匹配,在我们的例子中是ir.model.access 。 第一行需要是列名与模型的字段名完全匹配的标题。

对于标量值,您可以使用带引号的(如有必要,因为字符串本身包含引号或逗号)或不带引号的字符串。

当使用CSV文件编写many2one 字段时,Odoo首先尝试将列值解释为XML ID。 如果没有Odoo将当前模块名称添加为命名空间,并在ir.model.data 中查找结果。如果失败,模型的name_search 函数以列的值作为参数调用,返回的第一个结果。如果这也失败了,该行被认为是无效的并且Odoo会抛出一个错误。

重要笔记
请注意,从CSV文件读取的数据始终为noupdate=False ,并且没有方便的解决方法。这意味着您的附加组件的后续更新将始终覆盖用户所做的可能更改。如果您需要加载大量数据并且需要noupdate 这对您来说是个问题,请使用init 钩子加载CSV文件。

扩展内容

可以使用CSV文件导入one2manymany2many 字段,但有点棘手。通常,您最好分别创建记录并随后使用XML文件设置关系,或者使用设置关系的第二个CSV文件。

如果您确实需要在同一文件中创建关联记录,请对列进行排序,以便所有标量字段位于左侧,链接模型的字段位于右侧,列标题由链接字段的名称和链接的 模型的字段,用冒号分隔:

1
2
"id","name","model_id:id","perm_read","perm_read", "group_id:name"
"access_library_book_user","ACL for books","model_library_book",1, "my group"

这将创建一个名为my group 的组;您可以通过在右侧添加列来在组记录中写入更多字段。如果您需要关联多条记录,请重复该行并根据需要更改右侧列。鉴于Odoo使用前一行的值填充空列,因此您不需要复制所有数据,添加一行时,对想要填充值的关联模型字段以外的字段只需使用空值。

附加更新和数据迁移

您在编写附加模块时选择的数据模型可能会出现一些弱点,因此您可能需要在附加模块的生命周期中对其进行调整。为了在没有大量操作的情况下实现这一点,Odoo支持附加模块中的版本控制,并在必要时运行迁移。

实现步骤

假设在我们模块的早期版本中date_release 字段是一个字符字段,人们在其中写下他们认为合适的任何日期作为日期。我们现在意识到我们需要这个字段来进行比较和聚合,这就是我们想要将其类型更改为Date 的原因。

Odoo在类型转换方面做得很好,但是在这种情况下,我们是靠自己的,这就是为什么我们需要提供有关如何使用安装在数据库上的先前版本的模块来转换数据库的说明,其中当前版本可以运行。让我们尝试以下步骤:

  1. __manifest__.py 文件中添加版本:

    1
    'version': '13.0.1.0.1',
  2. migrations/13.0.1.0.1/pre-migrate.py 中提供预迁移代码:

    1
    2
    def migrate(cr, version):
    cr.execute('ALTER TABLE library_book RENAME COLUMN date_release TO date_release_char')
  3. migrations/13.0.1.0.1/post-migrate.py 中提供迁移后代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from odoo import fields
    from datetime import date
    def migrate(cr, version):
    cr.execute('SELECT id, date_release_char FROM library_book')
    for record_id, old_date in cr.fetchall():
    # check if the field happens to be set in Odoo's internal format
    new_date = None
    try:
    new_date = fields.Date.to_date(old_date)
    except ValueError:
    if len(old_date) == 4 and old_date.isdigit():
    # probably a year
    new_date = date(int(old_date), 1, 1)
    if new_date:
    cr.execute('UPDATE library_book SET date_release=%s',(new_date,))

如果没有此代码,Odoo会将旧的date_release 列重命名为date_release_moved 并创建一个新列,因为没有从字符字段到日期字段的自动转换。从用户的角度来看,date_release 中的数据将完全消失。

运行原理

第一个关键点是增加附加组件的版本号,因为迁移代码仅在版本变更时运行。在每次更新期间,Odoo将更新时清单中的版本号会写入ir_module_module 表。如果版本号包含三个或更少的组件,则版本号以Odoo的主要和次要版本作为前缀。在前面的示例中,我们明确命名了Odoo的主要版本和次要版本,这是一个很好的做法,但值为1.0.1 会产生相同的效果,因为在内部,Odoo会为带有自己主要版本和次要版本号的附加组件添加版本号前缀。通常使用长符号是一个好主意,因为您可以一眼看出插件适用于哪个版本的Odoo。

这两个迁移文件只是代码文件,不需要在任何地方注册。更新插件时,Odoo会将插件的版本(如ir_module_module 中所述)与插件清单中的版本进行比较。如果清单的版本更高(在添加Odoo的主要和次要版本之后),将搜索此插件的迁移文件夹以查看它是否包含中间版本的文件夹,直到当前更新版本的版本号。

然后在找到的文件夹中名称以pre- 开头的Python文件,加载它们,并为其定义一个名为migrate 的函数,该函数有两个参数。该函数以数据库游标作为第一个参数,当前安装的版本作为第二个参数调用。这一时间在Odoo查找插件定义的其它代码之前,因此你可以假定你的数据库结构对比此前版本没有做过任何修改。

在所有的pre-migrate 函数运行成功后,Odoo会加载模型和插件中声明的数据,这会导致数据库布局发生变化。鉴于我们在pre-migrate.py 中重命名了date_release ,Odoo将使用该名称创建正确的数据类型一个新列。

之后,使用相同的搜索算法,将搜索并执行迁移后的文件。在我们的例子中,我们需要查看每一个值,看看我们是否可以从中得到一些有用的东西;否则,我们将数据保持为NULL 。如果不是绝对必要,不要编写遍历整个表的脚本;在这种情况下,我们可能会编写一个很大且可读性差的SQL的switch语句。

重要提示
如果您只是想重命名列,则不需要迁移脚本。在这种情况下,您可以将相关字段的oldname 参数设置为该字段的原始列名,Odoo会自动更新它。

扩展内容

在迁移前和迁移后步骤中,您只能访问游标,如果您熟悉Odoo环境,这会变得不是很方便。在这个阶段使用模型可能会导致意想不到的结果,因为在预迁移步骤中,附加组件的模型尚未加载,并且在迁移后步骤中,由依赖于当前插件的插件定义的模型也尚未加载。 但是,如果这对您来说不是问题,也许是因为你想要使用你的插件所不涉及的模型或者是你已知这不会是一个问题的模型,那么就可以编写如下代码创建一个习惯的环境:

1
2
3
4
from odoo import api, SUPERUSER_ID
def migrate(cr, version):
env = api.Environment(cr, SUPERUSER_ID, {})
# env holds all currently loaded models

也可以看看
在编写迁移脚本时,您经常会遇到重复性任务,例如检查列或表是否存在、重命名或将一些旧值映射到新值。在这里重新发明轮子是令人沮丧和容易出错的;如果您负担得起额外的依赖,请考虑使用https://github.com/OCA/openupgradelib

从XML文件中删除记录

在前面的章节中,我们看到了如何从XML文件创建或更新记录。有时,您希望从依赖模块中删除以前创建的记录。这可以通过<delete> 标签来完成。

准备工作

在本节中,我们将从XML文件中添加一些类别,后删除它们。在实际情况下,您将从另一个模块创建此记录。但为简单起见,我们将在同一个XML文件中添加一些类别,如下所示:

1
2
3
4
5
6
<record id="book_category_to_delete" model="library.book.category">
<field name="name">Test Category</field>
</record>
<record id="book_category_not_delete" model="library.book.category">
<field name="name">Test Category 2</field>
</record>

实现步骤

有两种方法可以从XML文件中删除记录:

  • 使用先前创建的记录的XML ID:

    1
    <delete model="library.book.category" id="book_category_to_delete"/>
  • 使用搜索域:

    1
    <delete model="library.book.category" search="[('name', 'ilike', 'Test')]"/>

运行原理

您将需要使用<delete> 标签。要从模型中删除记录,您需要在模型属性中提供模型的名称。这是一个强制属性。

在第一种方法中,您需要提供先前从另一个模块的数据文件创建的记录的XML ID。在模块安装过程中,Odoo会尝试查找记录。如果找到给定XML ID的记录,它将删除该记录,否则将抛出错误。您只能删除从XML文件创建的记录(或具有XML ID的记录)。

第二种方法,需要在domain属性中传入domain 。在安装模块的过程中,Odoo会按这个domain搜索记录。如果找到记录,它将删除它们。如果没有记录与给定域匹配,则此选项不会抛出错误。使用此选项时要格外小心,因为它可能会删除用户的数据,因为搜索选项会删除与域匹配的所有记录。

警告
<delete> 在Odoo中很少使用,因为它很危险。如果您对此不小心,您可能会破坏系统。尽可能避免它。

从XML文件调用函数

您可以从XML文件创建所有类型的记录,但有时很难生成包含某些业务逻辑的数据。当用户在生产中安装依赖模块时,您可能希望修改记录。例如,假设您要创建一个模块来在线显示书籍。my_library 模块已经有一个image-cover 字段。 想象一下,在新模块中,您实现了减小图像大小并将其存储在新缩略图字段中的逻辑。现在,当用户安装这个模块时,他们可能已经有了书籍和图像。无法从XML文件中的<record> 标签生成缩略图。在这种情况下,您可以通过<function> 标签调用模型方法。

实现步骤

本节我们将使用上节中的代码。例如,我们将现有图书价格提高10美元。请注意,您可能会根据公司配置使用其他货币。

按照以下步骤从XML文件调用Python方法:

  1. library.book 模型中添加_update_book_price() 方法:

    1
    2
    3
    4
    5
    @api.model
    def _update_book_price(self):
    all_books = self.search([])
    for book in all_books:
    book.cost_price += 10
  2. 在数据XML文件中添加<function>

    1
    <function model="library.book" name="_update_book_price"/>

运行原理

在第1步中,我们添加了_update_book_price() 方法,该方法搜索所有书籍并将价格提高10美元。 以_ 开头的函数名称会被ORM认为是私有的,不能通过RPC调用。

在第2步中,我们使用了具有两个属性的<function> 标签:

  • model :声明方法的模型名称

  • name :要调用的方法的名称

当您安装此模块时,_update_book_price() 将被调用,书籍的价格将增加10美元。

重要笔记
始终将此功能与noupdate 选项一起使用。 否则,每次更新模块时都会调用它。

扩展内容

使用<function> 还可以向函数传递参数。假设您只想提高特定类别书籍的价格,并且希望将该金额作为参数发送。

为此,您需要创建一个接受类别作为参数的方法,如下所示:

1
2
3
4
5
@api.model
def update_book_price(self, category, amount_to_increase):
category_books = self.search([('category_id', '=', category.id)])
for book in category_books:
book.cost_price += amount_to_increase

要将类别和金额作为参数传递,需要使用eval 属性,如下:

1
2
3
<function model="library.book"
name="update_book_price"
eval="(ref('category_xml_id'), 20)"/>

当您安装该模块时,它会将给定类别的书籍的价格增加20美元。

Odoo14开发者指南第六章-管理模块数据【翻译】

https://www.junle.org/Odoo14开发者指南第六章-管理模块数据【翻译】/

作者

Junle

发布于

2022-06-16

更新于

2024-03-22

许可协议

评论