本博客包含多个文档和书籍的翻译,但有能力者推荐阅读英文原版

Odoo 12开发者指南第九章 高级服务端开发技巧

Odoo Alan 6个月前 (05-19) 1614次浏览 2个评论

全书完整目录请见:Odoo 12开发者指南(Cookbook)第三版

本章中,我们将讲解如下内容:

  • 更改执行动作的用户
  • 使用变更的上下文调用方法
  • 执行原生SQL查询
  • 编写向导来引导用户
  • 定义onchange方法
  • 在服务端调用onchange方法
  • 基于SQL视图定义模型
  • 添加自定义设置选项
  • 实现init钩子

引言

第六章 基本服务端部署中,我们学习了如何在模型类中编写方法、如何通过模型继承方法以及如何处理数据集。本章将讲解更为高级的话题,比如使用记录集的环境和操作onchange方法。

技术准备

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

本章中所使用的所有代码可通过GitHub仓库进行下载:https://github.com/PacktPublishing/Odoo-12-Development-Cookbook-Third-Edition/tree/master/Chapter09。

观看视频来查看代码实时操作:http://t.cn/AiWiA3uY

更改执行动作的用户

在编写业务逻辑代码时,你可能要通过不同的权限上下文来执行一些动作。典型的用例是通过跨过权限检查的Administrator权限执行一个动作。

本节将向你展示如何让普通用户通过使用sudo()来修改公司的电话号码。

准备工作

为更易于理解,我们将添加一个管理图书评级的新模型。新增一个名为library.book.rent的模型。可参考如下定义来添加这个模型:

你会需要添加一个表单视图、一个动作以及一个通过用户界面查看新模型的菜单项。还需要为librarian添加一个权限规则,这样他们可以发布供出租的图书。如果不了解这些知识,请参见第四章 创建Odoo插件模块

同时,你也可以使用GitHub上已经编写好的初始模块代码示例来节约一点时间。该模块位于Chapter09/r0_initial_module文件夹下。GitHub 代码示例请参见https://github.com/alanhou/odoo12-cookbook。

如何操作…

如果你测试过该模型,会发现只有拥有访问权限的图书管理员才能将图书标记为已借阅。非管理员用户无法自行借阅图书,他们需要借助于图书管理员借书。假设我们需要为非管理员用户添加一个自行借阅的功能。我们不为这些用户添加library.book.rent模型的访问权限并实现这一功能。

我们需要执行如下步骤来让普通用户可以借书:

  1. 在 library.book模型中添加book_rent()方法:
  2. 在该方法中,确保我们是对单条记录进行操作:
  3. 如果图书不可借阅则抛出一个警告:
  4. 使用超级用户来获取library.book.rent的空记录集:
  5. 通过相应的值新建一条图书借阅记录:
  6. 在图书的表单视图中添加按钮来通过用户界面触方这一方法:

重启服务并更新my_library来应用这些给出的修改。在更新后,我们将看在图书的表单视图中看到一个Rent this book 按钮。点击按钮会新那家一条借阅记录。非管理员用户可进行同样的操作。我们可以使用demo用户访问Odoo进行测试。

运行原理…

在第4步中,我们使用了sudo()。该方法返回一条带有新环境的新记录集,其中的用户与self中是不同的。在不加入参数调用时,sudo()会关联Odoo超级用户Administrator到环境中。通过这一sudo记录集的所有调用都通过新环境完成,因此也带有超级用户权限。要更好地了解它,从方法中删除.sudo()然后再点击Rent this book按钮。它会抛出Access Error并且用户无法再访问该模型。简言之,sudo()可以跳过所有权限规则。

如果你需要一个具体的用户,可以传递一个包含该用户或用户数据库 id 的记录集。如下脚本让我们可以使用公共用户搜索可见的图书。

ℹ️在使用sudo()时,对由谁创建或更新记录的动作都不进行跟踪记录。本节中公司的最后一次修改人为Administrator,而非最初调用create的用户。

位于https://github.com/OCA/server-backend/的社区插件base_suspend_security可用于处理这一问题。

扩展知识…

在不带参数使用sudo() 时,我们将上下文中的用户设置为了Odoo的超级用户。这个超级用户跨越Odoo的所有权限规则,包括权限控制列表和记录规则。默认用户拥有一个company_id字段来设置该实例(ID为1的那个)的主公司。对于多公司实例这会带来问题:

  • 如果你不小心,这一环境中新建的记录会与公司的超级用户相关联。
  • 如果你不小心,该环境的搜索记录会与数据库中的当前公司相关联,这表示你可能会向真实用户泄漏信息,更糟糕的是你可能通过将记录关联到不同的公司而默默地导致数据库的损坏。

小贴士:在sudo()时,应反复确认search()的调用不依赖于标准记录规则来过滤结果,并确保对create()的调用不依赖于使用当前用户字段如company_id来进行计算的默认值。

使用sudo()还会创建一个新的环境。这个环境会有一个初始空格记录集缓存,并且该缓存会独立于self.env的缓存进行增长。这会导致不必要的数据库查询。这种情况下,应避免在循环内新建环境并将这些环境的创建移到尽可能外面的层。

其它内容

参考如下内容获取更多信息:

使用变更的上下文调用方法

上下文是记录集环境的一部分。它用于传递来自用户界面用户的时区和语言等信息,以及动作中所指定的上下文参数。标准插件中的很多方法使用该上下文来对这些值调整它们的行为。有时会需要修改记录集的上下文来从方法调用获取所需要的结果或计算字段的所需结果。

本节将展示如何借助于上下文从相同的方法获取不同的输出。

准备工作

本节中我们将使用前面小节的my_library模块。在library.book.rent模型的表单视图中,我们将添加一个按钮来将图书标记为遗失。注意我们在图书的表单视图中已经有相同的按钮了,但此处我们将使用稍稍不同的行为在理解Odoo中上下文的使用。

如何操作…

我们需要执行如下步骤来添加按钮:

  1. 更新state字段的定义来添加一个遗失状态:
  2. 在library.book.rent的表单视图中添加一个Mark as lost按钮:
  3. 在library.book.rent模型中添加book_lost()方法:
  4. 在这个方法中,确保我们操作的是单条房记录,然后修改其状态:
  5. 在方法中添加如下代码来修改环境的上下文并调用方法来改变图书的状态为遗失:
  6. 更新 library.book模型的make_lost()方法来产生不同的行为:

运行原理…

第5步使用一些关键词参数调用self.book_id.with_context()。它返回一个带有添加到当前上下文键的新版本的book_id(一个library.book记录集)。这里我们只添加了一个键,avoid_deactivate=True,但是在需要时可以添加多个键。

第6步中,我们查看了该上下文是否为avoid_deactivate键带上了真值。我们避免了取消图书,这样即便是遗失了图书管理员仍然可以看到它们。

这仅仅是有关上下文的一个简单示例,你可以基于自己的要求在ORM的任何地方使用它。

扩展知识…

还可以将字典传递给with_context()。此时,该字典用作新的上下文,它会覆盖当前上下文。因此第5步可以这样编写:

使用with_context()包含创建一个新的环境实例。该环境会有一个初始空记录集缓存,它独立于self.env缓存进行增长。这会导致不必要的数据库查询。这种情况下,应避免在循环内新建环境并将这些环境的创建移到尽可能外面的层。

其它内容

参见如下小节来了解Odoo中更多的上下文知识:

执行原生SQL查询

大多数时候,你可以执行通过使用search()方法执行所需的操作。但是有时我们的所需不止于此,抑或是无使用domain语法(有些操作非常烧脑甚至是完全不可能)来进行表达,又或是查询需要对search()的多次调用,这会导致低效。

本节将展示如何使用原生SQL查询来获取用户借阅某本书天数的平均值。

准备工作

本节中我们将使用前面小节的my_library模型。为进行简化,我们只会在日志中打印结果,但在真实场景中,你会需要在业务逻辑中使用查询结果。在第十章 后端视图中,我们将在用户界面中展示查询的结果。

如何操作…

需要执行如下步骤来获取用户保留某本书的平均天数:

  1. 在library.book中添加average_book_occupation() 方法:
  2. 在该方法中,编写如下SQL查询:
  3. 执行该查询:
  4. 获取结果并进行日志记录:
  5. 在library.book模型的表单视图中添加一个按钮来触发我们的方法:

另忘了在这个文件中导入logging。然后重启并更新my_library模块。

运行原理…

在第2步中,我们声明了一个SQL SELECT查询。这会返回用户持有某本书的平均天数。如果在你PostgreSQL命令行运行这条查询,根据你的图书数据会得到类似下面的结果:

第3步对存储在self.env.cr中的数据库游标调用execute(方法。这会发送查询到PostgreSQL并进行执行。

第5步使用游标的 fetchall()方法来获取由查询所得到的行的列表。该方法返回一个行的列表,本例中为 [(‘Odoo 12 Development Cookbook’, 33), (‘PostgreSQL 10 Administration Cookbook’, 81)]。通过我们执行查询的表单,可以知道每行有两个值,第一个为书名,另一个是用户持有这本书的平均天数。然后我们进行了日志记录。

扩展知识…

self.env.cr中的对象是对psycopg2 cursor的轻度封装。以下的方法是最常需要执行的一部分方法:

  • execute(query, params):通过元组中参数值替换查询中标记为%s的参数来执行SQL查询。

    ℹ️警告:不要自行替换,这会带来SQL注入的风险。

  • fetchone():从数据库返回一行,以元组进行封装(即便是仅查询了一个字段)。
  • fetchall():以元组列表从数据库中返回所有行。
  • fetchalldict():以列名对值的映射字典列表返回数据库中的所有行。

有处理原生SQL查询时要非常小心:

  • 你跳过了所有应用层面的权限。请确保调用search([(‘id’, ‘in’, tuple(ids)]) 时过滤掉所有用户无权访问的 id 列表。
  • 你所做的修改不受插件模块中所设置的约束限制,除在数据库层面所强制的NOT NULL, UNIQUE和FOREIGN KEY约束。对于计算计算的重新计算触发器也是如此,因而可能会导致数据库的崩溃。

其它内容

编写向导来引导用户

第五章 应用模型为可复用模型功能使用抽象模型一节中,引用了models.TransientModel基类。这个类与常规的Model有很多的共通之处,不同点在于临时模型的记录会在数据库中定期地进行清除,因此称其为临时模型。它用于创建向导或对话框,来由用户在用户界面中填入并且通常用作执行对数据库中持久化记录的动作。

准备工作

本节中,我们将使用前面小节中的my_library模块。本节会添加一个向导,通过这一向导,图书管理员可以同时发布多本图书。

如何操作…

按照如下步骤来新建一个创建图书租赁记录的向导:

  1. 通过如下定义向模块添加一个新的临时模型:
  2. 添加在临时模型上执行动作的回调方法。向LibraryRentWizard类添加如下代码:
  3. 为模型创建一个表单视图。在模块视图中添加如下视图定义:
  4. 创建一个运行以及展示该向导的菜单入口。向模块菜单文件添加如下声明:

运行原理…

第1步定义了一个新的模型。除基类使用TransientModel代替Model外它与其它模型并无分别。TransientModel和Model又有一个共同的基类,名为BaseModel,如果你查看Odoo的源代码,会发现99%的工作都在BaseModel中执行,Model和TransientModel的内容都很少。

TransientModel只存在如下的变化:

  • 记录在数据库中会定时的删除,因此临时模型的数据表不会随时间不停增大。
  • 不能对TransientModel定义权限规则。任何人都可以创建记录,但仅有创建该记录的用户才能读取和使用这条记录。
  • 在TransientModel中不能定义引用普通模型的One2many字段,因为这将在持久化模型中添加关联到临时数据的列。在这种情况下使用Many2many关联。当然,你可以在临时模型之前定义Many2one和One2many字段关联。

我们在模型中定义了两个字段:一个用于存储借书的成员,另一个存储所借阅的书籍。我们可以添加其它标量字段,来记录预计归还日期等。

第2步为点击第3步中所定义按钮调用的向导类添加了代码。这段代码从向导中读取值并为每本书创建library.book.rent记录。

第3步为我们的向导定义了一个视图,参见第十章 后端视图定义文档样式表单一节获取更多详情。这里的重点是footer中的按钮,类型属性设置为了object,表示在用户点击该按钮时,会调用按钮name属性所指定的同名方法。

第4步中确保我们在应用的菜单中有一个向导的入口。我们在动作中使用了target=’new’ ,这样该表单视图会在当前表单上以对话框形式展示。参见第十章 后端视图中的添加菜单项和窗口动作一节来了解详情。

Step 4 ensures that we have an entry point for our wizard in the menu of the application. We use target=’new’ in the action, so that the form view is displayed as a dialog box over the current form. Refer to the Adding a menu item and window action recipe in Chapter 10, Backend Views, for details.

扩展知识…

下面是一些优化向导的贴士:

使用上下文来计算默认值

我们所展示的向导要求用户在表单中输入成员名。在网页客户端中有一个功能可用来节约一些输入。在执行动作时,上下文中会更新一些值,并可由向导所使用:

active_model这是与动作相关联的模型名。通常为在屏幕上所展示的模型。
active_id这表明单条记录是活跃的并且提供了该记录的 ID。
active_ids如果选择了多条记录,这将是带有 ID 的列表。这在树状视图中选择多项并触发动作时发生。在表单视图中,所获取的为 active_id。
active_domain这是向导将要操作的其它域。

这些值可用于计算模型的默认值,或甚至直接在按钮的调用方法中进行计算。我们来提升一下本节中的示例,如果 res.partner 模型的表单视图中展示了一个启动向导的按钮,向导创建的上下文中会包含{‘active_model’: ‘res.partner’, ‘active_id’: }。这种情况下,我们应定义member_id字段来获取由如下方法所计算的默认值:

向导和代码复用

第2步中,我们可以删除向导中的for循环,并在假定len(self) 为1时,我们可以在方法的开头添加self.ensure_one()如下:

在方法的开头添加self.ensure_one()会确保self中的记录条数为1。如果self中的记录条数多于1会抛出错误。

但我们推荐使用这一部分中的代码,因为这让我们可以通过为向导创建记录复用代码中其它部分的向导,将它们放在单个记录集中(参见第六章 基本服务端部署中的合并记录集一节了解如何实现),然后对记录集调用add_book_rents()。这里的代码很简单,无需跳过所有循环来记录某些书由不同成员借阅。但是在Odoo实例中,有些操作非常的复杂,带上可以实现正确操作的向导会非常的好。在使用这些向导时,确保你源代码中是否使用了上下文中的active_model/active_id/active_ids keys。如果使用了,需要传递一个自定义上下文(参见使用变更的上下文调用方法一节)。

重定向用户

第2步中的方法没有任何返回。这会导致向导对话框在执行完动作后关闭。另一种可能是让方法返回带有ir.action中字段的字典。此时,网页客户端会像用户点击了菜单入口那样处理该动作。BaseModel中定义get_formview_action()方法可用来进行实现。例如,如果我们想要展示刚刚借阅书籍的成员的表单视图,我们可以编写如下代码:

这会从该向导创建一个借阅了图书的成员列表(实例情况中,在用户界面中调用该向导时仅会有一个成员)并创建一个动态的动作,来使用指定的 ID 展示成员。

重定向用户技术可用于创建包含多个逐个执行步骤的向导。向导中的每一步可使用前一步中的值。通过提供Next按钮来调用向导中定义了更新向导某些字段的方法,并返回在相同更新后向导中重新展示的动作以及准备好下一个步骤。

定义onchange方法

在编写Odoo模型时,常常会有一些字段交叉关联。我们在第五章 应用模型中的向模型添加约束验证一节中学习过如何在字段中指定约束。本节讲解稍有不同的概念。这里在用户界面中一个字段被修改时调用onchange,来网页客户端中更新记录其它字段的值,通常是在表单视图中。

我们将通过提供类似编写向导来引导用户一节中所定义的向导进行讲解,但它可用于记录图书归还。在向导中设置成员时,图书的列表会更新为成员当前所借阅的书籍。虽然我们在TransientModel上演示onchange方法,这些功能也可以用于普通Model。

准备工作

本节中我们将使用编写向导来引导用户一节中的my_library模块。我们将创建一个向导来归还所借阅图书。这会添加一个onchange方法,它会在图书管理员选择成员字段时自动填入图书。

你需要通过为向导定义如下临时模型来进行准备:

最后,你需要为向导定义视图、动作和菜单入口。这些部分读者可作为练习自行添加。

如何操作…

在用户修改时自动提供要归还的书籍,我们需要在LibraryReturnsWizard步骤中添加onchange方法,定义如下:

运行原理…

onchange方法使用@api.onchange装饰器,传递变化的字段,因而会触发该方法的调用。本例中,我们告诉用户界面在borrower_id发生变更时应调用该方法。

在方法体中,我们搜索当前由成员借阅的图书,并且我们使用属性分配来更新向导中的book_ids属性。

ℹ️@api.onchange装饰器处理发往网页客户端的视图变更来为字段添加一个on_change属性。这在老API中为手动操作。

扩展知识…

onchange的基础用法是在用户界面中其它字段发生变化时为字段计算新值,本节中我们也看到了。

在方法体中,我们获取对记录当前视图中展示的字段的访问,但不需要是模型的所有字段。这是因为可在用户界面中创建记录并还未存储到数据库中时调用。在onchange方法内,self 处于一种特殊状态,表现为self.id其实并不是整型,而是odoo.models.NewId的实例。因此我们不应在onchange方法以内对数据库进行任何修改,原因在于用户可能会取消记录的创建,而在编辑的过程中并不会对onchange方法所做的修改进行回滚。可以使用self.env.in_onchange()和self.env.in_draft()对此进行查看,前者在当前执行上下文为onchange方法时返回True,后者在self还未在数据库中提交时返回True。

此外,onchange可以返回一个Python字段。字典中可以有如下的键:

  • warning:值应为一个字典,其中有title和message键,分别包含着对话框的标题和内容,在onchange方法运行时会进行展示。这在发生不连续或潜在问题时用于引起用户的注意。
  • domain:值应为将字段名映射到域的字典。用于在想要根据另一个字段的值修改One2many字段的域时。

例如,假定我们在 library.book.rent模型中对expected_return_date有一个固定的值的集合,并且希望在成员有延迟未还的图书时显示警告。我们还会希望将图书的选择限制为用户当前所借阅的图书。可以重写onchange方法如下:

在服务端调用onchange方法

第六章 基本服务端部署中的新建记录更新记录集中记录值小节中提到了这些操作不自动调用onchange方法。但是在一些用例中,调用这些操作又很重要,因为它们在所创建或所更新记录中更新重要的字段。当然, 你可以自己完成所需计算,但有时不可能做到,因为onchange可由你不知道的安装在实例中的第三方插件所添加或修改。

本节讲解如何通过在创建记录前手动触发onchange方法对记录的onchange方法进行调用。

准备工作

更改执行动作的用户一节中,我们添加了一个Rent this book按钮来让非图书管理员用户来自己借阅图书。现在我们需要对归还图书做相同操作,但不是编写归还图书的逻辑,而是仅仅使用定义onchange方法一节中所创建的图书归还向导。

如何操作…

本节中,我们将手动创建library.return.wizard模型的一条记录。我们希望onchange方法来为我们计算归还的图书。需要执行如下步骤来进行实现:

  1. 在library.book模型中创建return_all_books方法:
  2. 为library.return.wizard获取一个空记录集:
  3. 准备创建新向导记录的值。这里我们将使用当前用户的成员ID来作为borrower_id,但如果你想要将这个按钮放在res.parnter模型上的话,可以使用self.id:
  4. 为向导获取onchange的详情:
  5. 获取onchange方法的结果:
  6. 通过新向导的值合并这些结果:
  7. 创建向导:

运行原理…

有关第1至3步的讲解,参见第六章 基本服务端部署新建记录一节。

第4步对该模型调用_onchange_spec方法,不传递参数。这一方法会获取由另一个字段的变更所触发的更新。这通过检查模型的表单视图来实现(记住onchange方法通常由网页客户端所调用)。

第5步中调用了模型的onchange(values, field_name, field_onchange) 方法,有三个参数:

  • values:我们要对记录设置的值的列表。你需要为所有需由onchange方法修改的字段提供值。本节中,基于这一原因我们将book_ids设置为False。
  • field_name:我们希望触发onchange方法的字段列表。你可以传递一个空列表,ORM会使用值中所定义的字段。但是,我们会经常想要手动指定这一列表来在不同的字段更新相同的字段时手动控制运行的顺序。
  • field_onchange:第4步中所计算的onchange详情。这一方法查找应调用哪些onchange方法,以及调用的顺序,它返回一个字典,其中包含如下键:
    • value:这是一个新计算字段值的字典。这个字典仅包含传递给onchange()的values参数的键。注意Many2one字段会映射到包含 (id, display_name)的元组来进行对网页客户端的优化。
    • warning:这是一个包含在网页客户端展示给客户的警告信息字典。
    • domain:这是一个映射字段名到新有效域的字典。

通常,在手动操作onchange方法时,我们只关心value中有什么。

第6步通过onchange所计算值来更新我们的初始值字典。我们处理与Many2one字段对应的值来仅保留id。这么做我们利用了这些字仅为那些返回值为一个元组的字段。

最后,第7步中创建了记录。

扩展知识…

如果你需要在修改字段后调用onchange方法,代码是相同的。你仅需获取记录值的一个字典,这可在修改字段后使用values = dict(record._cache)来获取。

其它内容

如果想要了解创建和更新记录的更多知识,参见第六章 基本服务端部署新建记录更新记录集中记录值小节。

基于SQL视图定义模型

在进行插件模块的设计时,我们对类中由Odoo映射到数据表的数据建模。我们应用了一些知名的设计原则,比如关注点分享和数据归一化。但在模块设计的随后阶段,它可用于为同一张表中的多个模型累加数据,可能对它们执行一些运算,尤其是报告或生成仪表盘。要进行简化,以及利用Odoo中PostgreSQL数据库引擎底层的全部强大之处,可以定义基于PostgreSQL视图而非数据表的只读模型。

本节中,我们将复用本章中编写向导来引导用户一节的租赁模型,并且我们会新建一个模型来让收集图书和作者数据更为容易。

准备工作

本节中,我们将使用前一节中的my_library模块。我们会创建一个调用library.book.rent.statistics的新模型来保留统计数据。

如何操作…

按照如下步骤通过基于PostgreSQL视图创建新模型:

  1. 新建一个模型并将_auto class类属性设置为False
  2. 声明想要在该模型中看到的字段,将它们设置为readonly:
  3. 定义init()方法来创建视图:
  4. 现在可以为新模型定义视图了。透视表视图对于挖掘数据尤为有用(参见第十章 后端视图)。
  5. 不要忘记为新模型定义一些权限规则(参见第十一章 权限安全)。

运行原理…

通常,Odoo会为通过为数据列使用字段定义的模型新建一张表。实际上,这是因为在BaseModel类中,_auto属性默认为True。在第1步中,通常将这个类属性设为False,我们告诉Odoo我们将自己管理它。

第2步中,我们定义将由Odoo使用的一些字段来生成数据表。我们将它们标记为readonly=True,这样视图不会启用无法保存的修改,因为PostgreSQL的视图是只读的。

第3步中定义了init()方法。这个方法通常什么也不做,它在_auto_init()之后调用(在_auto = True时负责数据表的创建,否则什么也不做),并且我们使用它来创建一个新的SQL视图(或在模型升级时更新已有视图)。视图创建查询必须创建一个包含匹配Model字段名的字段名的视图。

小贴士:这是一个常见错误,这种情况下,忘记在视图定义查询中重命名该字段,会在Odoo无法查找到该字段时产生错误信息。

注意我们还需要加入一个名为ID包含唯一值的整型列。

扩展知识…

还有可能在这种模型中包含一些计算和关联字段。唯一的限制是这些字段不能被存储(因此你不能使用它们来分组记录或进行搜索)。但是在前例中,我们可通过添加一字段来使用图书的编辑器,定义如下:

如果你需要使用publisher分组,需要通过在视图定义中添加该字段来进行存储,更不是使用关联字段。

添加自定义设置选项

在Odoo中,你可以通过Settings选项设置可选功能。用户可以随时启用或禁用该选项。本节中我们将描述如何创建设置选项。

准备工作

在前面的小节中,我们添加了一些按钮,这样非图书管理员用户可以借阅及归还图书。对每个图书馆并非都是如此,因此我们会创建设置选项来启用及禁用这一功能。我们将通过隐藏这些按钮来实现。本节中,我们会使用前面小节中相同的my_library模块。

如何操作…

按照如下步骤来创建自定义设置选项:

  1. 在my_library/security/groups.xml文件中添加一个新分组:
  2. 通过继承res.config.settings模型来添加新字段:
  3. 通过xpath在已有的settings视图中添加这一字段(更多详情,请参见第十章 后端视图):
  4. 为Settings添加一个菜单及一些动作:
  5. 修改图书表单视图中的按钮燕添加一个my_library.group_self_borrow分组:

重启服务并更新my_library模型来应用修改。

运行原理…

Odoo中所有的设置选项都在res.config.settings模型中进行添加。res.config.settings 是一个临时模型。第1步中,我们创建了一个新的权限组。我们将使用这个组来创建隐藏和显示按钮。

第2步中,我们通过继承它在res.config.settings模型中添加了一个新的布尔字段。我们添加了一个implied_group属性,值为my_library.group_self_borrow。这个分组会在admin通过该布尔字段启用或禁用选项时被分配给所有的odoo用户。

Odoo设置使用一个表单视图来在用户界面中展示settings选项。所有这些选项通过外部ID,base.res_config_settings_view_form在单个表单视图进行添加。第3步中,我们通过继承这一个设置表单视图来在用户界面中添加选项。第十章 后端视图中,我们将进行更深入的学习。在表单定义中,我会发现这一选项的属性数据键值为模块名称。仅在向Settings添加在整个新的选项卡才会需要。否则,你只需通过xpath对已有模块的Settings选项卡中添加选项。

第4步中,我们添加了一个动作及一个菜单来在用户界面访问配置选项。你会需要传递动作中的 {‘module’ : ‘my_library’}上下文来在点击菜单时默认打开my_library模块的Settings选项卡。

第5步中,我们向按钮添加了my_library.group_self_borrow组。借助这一个组,Borrow和Return按钮会根据settings选项隐藏或显示。

然后,你会看到一个该图书馆的单独Settings选项卡,其中,可心看到一个布尔字段用于启用或禁用自借阅选项。在启用或禁用这一选项时,背后Odoo会对所有odoo用户应用或删除implied_group。因为我们在按钮上添加了组,按钮会在用户拥有组时显示,而在用户没有组时隐藏。在第十一章 权限安全中,我们会深入地学习权限组。

扩展知识…

还有一些其它方式来管理设置选项。其中之一是分离功能到新模块中并通过选项安装或卸载这些模块。你会需要使用以module_为前缀加模块名的名称来添加一个布尔字段进行实现。例如,我们新建一个名为my_library_extras的模块,你会需要添加一个如下的布尔字段:

在启用或禁用该选项时,odoo会安装或卸载my_libarary_extras模块。

实现init钩子

第七章 模块数据中,我们学习了如何通过XML或CSV文件添加、更新及删除记录。但有时,业务用例非常复杂,无法通过使用数据文件来进行解决。这些情况下,可以在声明文件中使用init钩子来执行所需要的操作。

准备工作

我们将使用前一节中相同的my_library模块。本节中为进行简化,我们仅通过post_init_hook来创建一些图书记录。

如何操作…

按照如下步骤来添加post_init_hook:

  1. 在__manifest__.py文件中通过post_init_hook键来注册这个钩子:
  2. 在__init__.py文件中添加add_book_hook()方法:

运行原理…

在第一步中,我们在声明文件文件中通过add_book_hook值注册了post_init_hook。这表示在模块安装之后,Odoo会在__init__.py中查找add_book_hook方法。如果找到,它会使用数据库游标和 registry调用该方法。

第2步中,我们声明了add_book_hook()方法,在模块安装后会被调用。我们通过该方法创建了两条记录。在实际情况中,可以在本息编写复杂的业务逻辑。

本例中,我们学习了post_init_hook,但Odoo还支持另外两种钩子:

  • pre_init_hook:这个钩子会在开始安装模块时触发。它与post_init_hook正好相反,会在当前模块安装前触发。
  • uninstall_hook:这个钩子会在你卸载该模块时触发。它多用于模块需要垃圾回收机制时。
喜欢 (2)
[]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. 本节讲解如何通过在创建记录前手动触发onchange方法对记录的onchange方法进行调用。这句话什么意思?
    Davis2019-09-23 20:51 回复
  2. 谢谢alan
    246782019-06-21 20:52 回复