Odoo 12開發(fā)者指南第七章 模塊數(shù)據(jù)

全書完整目錄請見:Odoo 12開發(fā)者指南(Cookbook)第三版

本章中罗岖,我們將講解如下小節(jié):

  • 使用外部ID和命名空間
  • 使用XML文件加載數(shù)據(jù)
  • 使用noupdate和forcecreate標(biāo)記
  • 使用CSV文件加載數(shù)據(jù)
  • 插件更新和數(shù)據(jù)遷移
  • 從XML文件中刪除記錄
  • 從XML文件中調(diào)用函數(shù)

引言

本章中,我們將學(xué)習(xí)如何添加在安裝時(shí)可提供數(shù)據(jù)的插件模塊。這對于提供默認(rèn)值以及添加視圖描述切端、菜單或動作等元數(shù)據(jù)都非常有用。另一個(gè)重要的用途是提供演示數(shù)據(jù)群井,勾選了加載演示數(shù)據(jù)復(fù)選框時(shí)會數(shù)據(jù)庫創(chuàng)建的同時(shí)載入數(shù)據(jù)鸥诽。

技術(shù)準(zhǔn)備

本章的技術(shù)要求包含在線Odoo平臺。

本章中的所有代碼可通過GitHub代碼倉庫進(jìn)行下載:https://github.com/PacktPublishing/Odoo-12-Development-Cookbook-Third-Edition/tree/master/Chapter07琴拧。

實(shí)時(shí)代碼操作請觀看如下視頻:http://t.cn/Ailakrsh

使用外部ID和命名空間

本書中到此為上降瞳,我們在視圖、菜單和動作等區(qū)域使用了XML ID蚓胸。但并沒有學(xué)習(xí)XML ID實(shí)際是什么挣饥。這一節(jié)會帶給你更深的理解。

如何操作...

我們將在已有記錄中進(jìn)行寫入來演示如何使用跨模塊引用:

  1. 在你的模塊聲明文件中添加數(shù)據(jù)文件:
'data': [
      'data/data.xml',
    ],
  1. 修改主公司的名稱:

      <field name="name">Packt publishing</field>
    </record>
  1. 設(shè)置主公司的成員作為出版商:

      <field name="publisher_id" ref="base.main_partner" />
    </record>

在安裝這一模塊時(shí)沛膳,公司會被重命名并且下一部分中的圖書會被分配給成員扔枫。在該模塊的后續(xù)更新中,只會分配出版商锹安,但公司名稱不做修改短荐。

運(yùn)行原理...

XML ID是一個(gè)引用數(shù)據(jù)庫中某記錄的字符串倚舀。ID本身是ir.model.data模型中的記錄。這一模型的行包含聲明XML ID標(biāo)識字符串和引用ID的模塊忍宋。每次我們寫入XML ID時(shí)痕貌,Odoo會檢查該字符串是否帶有命名空間(即它是否只包含一個(gè)點(diǎn)標(biāo)記),如果不帶有糠排,它會添加當(dāng)前模塊名作為命名空間舵稠。然后,它查找ir.model.data中是否有指定名稱的記錄入宦。若有哺徊,所列出字段會執(zhí)行一個(gè)UPDATE語句。若沒有乾闰,則執(zhí)行一條CREATE語句落追。這樣你可以像前面那樣在記錄已存在時(shí)添加部分?jǐn)?shù)據(jù)。

小貼士:在其它模塊中定義對記錄做修改外涯肩,部分?jǐn)?shù)據(jù)的一個(gè)廣泛應(yīng)用是使用快捷元素來以便捷的方式來創(chuàng)建記錄并在記錄中寫入字段轿钠,而快捷元素并不提供支持:

<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>

ref函數(shù),在本章中使用XML文件加載數(shù)據(jù)一節(jié)還會使用到宽菜,如果xml文件中的ref屬性值字符串未指定所在模塊谣膳,則在當(dāng)前模塊記錄的XML ID中搜索,如找不到則報(bào)錯(cuò)铅乡。如果XML記錄的id屬性沒有指定所在模塊继谚,則生成記錄時(shí)會自動加上當(dāng)前模塊名作為命名空間。

擴(kuò)展知識...

遲早你會需要在代碼中通過XML ID訪問記錄阵幸。這種情況下使用self.env.ref()函數(shù)花履。這返回所引用記錄的瀏覽記錄。注意在這里你要保持傳入完整的XML ID挚赊。一個(gè)完整XML ID的示例為:<module_name>.<record_id>诡壁。可以在用戶界面中看到任意記錄的XML ID荠割。但需要激活Odoo的開發(fā)者模式妹卿。

參見第一章 安裝Odoo開發(fā)環(huán)境來在 Odoo 中激活開發(fā)者模式。在激活了開發(fā)者模式之后蔑鹦,打開你希望查看XML ID的記錄的表單視圖夺克。會在頂欄中看到一個(gè)調(diào)試圖標(biāo)。在該菜單中嚎朽,點(diǎn)擊View Metadata選項(xiàng)铺纽。參見如下截圖:

TODO

其它內(nèi)容

參見本章中使用noupdate和forcecreate標(biāo)記一節(jié)來了解為何公司名僅在模塊安裝時(shí)才會進(jìn)行修改。

使用XML文件加載數(shù)據(jù)

使用第五章 應(yīng)用模型中的數(shù)據(jù)模型哟忍,我們將添加一本書和一位作者來作為演示數(shù)據(jù)狡门。我們還會添加一個(gè)知名的出版社來作為模塊中的常規(guī)數(shù)據(jù)陷寝。

如何操作...

創(chuàng)建兩個(gè)XML文件并在manifest.py文件中關(guān)聯(lián)它們。

  1. 在你的聲明文件中的demo版塊中添加一個(gè)名為 data/demo.xml的文件:
'demo': [
      'data/demo.xml',
    ],
  1. 在該文件中添加如下內(nèi)容:
<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>
  1. 在聲明文件的data版塊中添加一個(gè)名為data/data.xml 的文件:
'data': [
      'data/data.xml',
      ...
    ],
  1. 在data/data.xml 文件中加入如下 XML 內(nèi)容:
<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>

此時(shí)若更新該模塊其馏,會看到我們所創(chuàng)建的出版社凤跑,并且如果像第四章 創(chuàng)建Odoo插件模塊中所指出的那樣啟用了演示數(shù)據(jù),還可以看到這本書以及其作者叛复。

運(yùn)行原理...

演示數(shù)據(jù)在技術(shù)上普通數(shù)據(jù)相同饶火。不同之外在于前者通過聲明文件中的 demo 鍵拉取數(shù)據(jù),后者通過 data 鍵來拉取數(shù)據(jù)致扯。使用<record>元素來創(chuàng)建記錄,它有一個(gè)必填的id和model屬性当辐。對于 id 屬性抖僵,參見使用外部ID和命名空間一節(jié),model屬性引用模型的_name屬性缘揪。然后耍群,使用<field>元素來填入數(shù)據(jù)庫中列,這在你所命名的模型中定義找筝。模型還決定哪些字段是必填的并且有可能定義了默認(rèn)值蹈垢。在這種情況下,你無需顯式地給這些字段賦值袖裕。在第2步中曹抬,<field>元素可以在標(biāo)量值的情況下包含簡單文本值。如果你需要傳遞一個(gè)文件的內(nèi)容(例如設(shè)置圖片時(shí))急鳄,使用<field>元素的file屬性并傳遞相對插件路徑的文件名谤民。

設(shè)置引用有兩種方式。最簡單的一種是使用ref屬性疾宏,可用于many2one字段张足,僅需包含所引用記錄的XML ID。對于one2many和many2many字段坎藐,我們需要使用eval屬性为牍。這是一種通用目的屬性,可用于運(yùn)行Python代碼來作為字段值使用岩馍,例如使用strftime('%Y-01-01')來填充date字段碉咆。X2many中應(yīng)使用三個(gè)元素元組列表,元組的第一個(gè)值決定所要采取的操作兼雄。在eval屬性內(nèi)吟逝,我們可以訪問一個(gè)名為ref的函數(shù),它返回以字符串傳入的XML ID 對應(yīng)的數(shù)據(jù)庫ID赦肋。這讓我們可以無需知道不同數(shù)據(jù)庫中可能不同的原始 ID 即可引用記錄块攒,如下所示:

  • (2, id, False):它會刪除通過數(shù)據(jù)庫 id 所關(guān)聯(lián)的記錄励稳。元組的第三個(gè)元素被忽略。
  • (3, id, False):它從one2many字段通過id,取消記錄的關(guān)聯(lián)囱井。注意這個(gè)操作不會刪除原記錄驹尼,已有記錄保持原樣。元組的最后一個(gè)元素也被忽略庞呕。
  • (4, id, False):它添加一個(gè)已有記錄 id的關(guān)聯(lián)新翎,元組的最一個(gè)元素被忽略。這應(yīng)該是你會最常使用到的住练,通常伴隨ref函數(shù)來通過其XML ID來獲取記錄的數(shù)據(jù)庫 ID地啰。
  • (5, False, False):它會切斷所有關(guān)聯(lián),但仍保持所關(guān)聯(lián)的記錄的完整性讲逛。
  • (6, False, [id, ...]):它會清除當(dāng)前引用的記錄來將它們替換為 ID 列表中包含的記錄亏吝。元組的第二個(gè)元素被忽略。

??注意數(shù)據(jù)文件中的順序很重要盏混,并且數(shù)據(jù)文件中的記錄僅能引用該文件此前列表中所定義的記錄蔚鸥。這也是為什么你需要保持查看模塊是否在空數(shù)據(jù)庫中安裝,因?yàn)樵陂_發(fā)過程中许赃,你會經(jīng)常在各處添加記錄止喷,能夠使用的前提是后續(xù)所定義記錄通過前幾次更新已存在于數(shù)據(jù)庫中。演示數(shù)據(jù)總是會通過data鍵后的文件進(jìn)行載入混聊,這也是本例中的引用可以生效的原因弹谁。

擴(kuò)展知識...

雖然基本上你可以對記錄元素做任何操作,開發(fā)人員可以使用一些快捷元素來便捷地創(chuàng)建某種類型的記錄技羔。這包含menu item, template和 act window僵闯。參見第十章 后端視圖第十六章 網(wǎng)頁客戶端開發(fā)來獲取更多相關(guān)信息。

一個(gè)字段元素還可以包含function元素藤滥,它調(diào)用模型中的方法來提供字段值鳖粟。參見從XML文件中調(diào)用函數(shù)一節(jié),其中我們僅通過調(diào)用函數(shù)來在應(yīng)用中直接繞過加載機(jī)制并寫入數(shù)據(jù)庫拙绊,

前述列表中沒有包含0和1向图,因?yàn)樵谳d入數(shù)據(jù)庫這兩者并沒有什么用處。為保持完整性标沪,說明如下:

  • (0, False, {'key': value}):它會新建所引用模型的記錄榄攀,字段值由第3個(gè)位置參數(shù)的字典填寫。元組的第二個(gè)元素被忽略金句。因?yàn)檫@些元素不包含XML ID并在每次更新模塊時(shí)運(yùn)行檩赢,會導(dǎo)致重復(fù)數(shù)據(jù),最好避免使用违寞。取代方案是在其自身記錄元素中創(chuàng)建記錄贞瞒,并按照如何操作一節(jié)講解的進(jìn)行關(guān)聯(lián)偶房。
  • (1, id, {'key': value}):它可用于寫入已關(guān)聯(lián)的記錄。由于上述的同樣原因军浆,應(yīng)避免在你的XML文件中使用這種語法棕洋。

這些語法與我們在第六章 基本服務(wù)端部署新建記錄更新記錄集中記錄值小節(jié)中所講解的相同。

使用noupdate和forcecreate標(biāo)記

大部分的插件模塊擁有不同類型的數(shù)據(jù)乒融。有些數(shù)據(jù)需要存在來讓模塊正常運(yùn)作掰盘,另一些數(shù)據(jù)不應(yīng)由用戶修改,大部分?jǐn)?shù)據(jù)都可以供用戶修改赞季,僅出于方便目的予以提供愧捕。本節(jié)會詳細(xì)講解這些不同類型的數(shù)據(jù)。首先申钩,我們將在已有記錄中寫入一個(gè)字段晃财,然后我們會創(chuàng)建一個(gè)在模塊更新時(shí)會被創(chuàng)建的記錄。

如何操作...

我們可以通過在 Odoo 中加載數(shù)據(jù)時(shí)設(shè)置<odoo>元素或<record>元素自身的某些屬性來施加不同的行為典蜕,

  1. 添加在安裝時(shí)會創(chuàng)建但后續(xù)更新不同更新的出版商。但在用戶刪除它時(shí)會被重新創(chuàng)建:

      <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>
  1. 添加一個(gè)在插件更新時(shí)不會修改且用戶刪除后不會重建的圖書分類:

      <record id="book_category_all"
        model="library.book.category"
        forcecreate="false">
        <field name="name">All books</field>
      </record>
    </odoo>

運(yùn)行原理...

<odoo>元素可包含一個(gè)noupdate屬性罗洗,在 ir.model.data記錄中由第一次讀取所包含的數(shù)據(jù)記錄創(chuàng)建愉舔,因此成為數(shù)據(jù)表中的一個(gè)字段。

在Odoo安裝插件時(shí)(稱為 init 模式)伙菜,不論noupdate為true或false都會寫入所有記錄轩缤。在更新插件時(shí)(稱為update模式),會查看已有的XML ID來確定是否設(shè)置了noupdate標(biāo)記贩绕,如是火的,則會忽略準(zhǔn)備寫入到該XML ID 的元素。在用戶刪除該記錄時(shí)則并非如此淑倾,因此你可以通過在update模式下設(shè)置記錄的forcecreate標(biāo)記為false來強(qiáng)制不重建noupdate記錄馏鹤。

??在老版本的插件中(版本8.0及以前),你經(jīng)常會發(fā)現(xiàn)<openerp>元素中包含一個(gè)<data>元素娇哆,其中又包含<record>及其它元素湃累。這仍然可用,但屬于被淘汰的方式“郑現(xiàn)在治力,<odoo>, <openerp>和<data>的方法完全一致,它們作為XML數(shù)據(jù)的一個(gè)包裹勃黍。

擴(kuò)展知識...

如果在使用noupdate標(biāo)記時(shí)你依然想要加載記錄宵统,可以在運(yùn)行Odoo服務(wù)時(shí)帶上--init=your_addon或-i your_addon參數(shù)。這會強(qiáng)制Odoo重載記錄覆获。這還會重建已刪除的記錄马澈。注意如果模塊繞過了XML ID機(jī)制的話這可能會導(dǎo)致重復(fù)記錄以及關(guān)聯(lián)安裝的報(bào)錯(cuò)瓢省,例如Python代碼中由<function>標(biāo)簽所調(diào)用來創(chuàng)建記錄時(shí)。

通過這一代碼箭券,你可以繞過任意noupdate標(biāo)記净捅,但首先請確保這確實(shí)是你所需要的。另一個(gè)解決這一場景的方案是編寫一個(gè)遷移腳本辩块,參見插件更新和數(shù)據(jù)遷移一節(jié)蛔六。

其它內(nèi)容

Odoo還使用XML ID來追蹤插件升級后所刪除的數(shù)據(jù)。如果記錄在更新前通過模塊命名空間獲取到一個(gè)XML ID废亭,但在更新時(shí)重置了該XML ID国章,記錄會因被視作已過期而從數(shù)據(jù)庫中刪除。有關(guān)這一機(jī)制更深入的討論豆村,請見插件更新和數(shù)據(jù)遷移一節(jié)液兽。

使用CSV文件加載數(shù)據(jù)

雖然可以通過XML文件來進(jìn)行所需任意操作,但在提供大量數(shù)據(jù)時(shí)這種格式并不是很方便掌动,尤其是現(xiàn)在很多人都習(xí)慣于使用Calc或其它數(shù)據(jù)表軟件處理數(shù)據(jù)四啰。CSV格式的另一個(gè)優(yōu)勢在于它是使用標(biāo)準(zhǔn)導(dǎo)出函數(shù)導(dǎo)出數(shù)據(jù)的格式。本節(jié)中粗恢,我們來學(xué)習(xí)導(dǎo)入類表格數(shù)據(jù)柑晒。

如何操作...

最初,訪問控制列表(ACL眷射,參見第十一章 權(quán)限安全)是通過CSV文件加載的一種數(shù)據(jù)類型匙赞。

  1. 在數(shù)據(jù)文件中添加security/ir.model.access.csv:
'data': [
      ...
      'security/ir.model.access.csv',
     ],
  1. 在這個(gè)文件中添加我們圖書的ACL(我們已經(jīng)通過第四章 創(chuàng)建Odoo插件模塊添加訪問權(quán)限一節(jié)添加了一些記錄):
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

現(xiàn)在我們有了一個(gè)ACL,它允許普通用戶讀取圖書記錄妖碉,但無法編輯涌庭、創(chuàng)建或刪除這些記錄。

運(yùn)行原理...

你僅需將所有數(shù)據(jù)文件放到聲明文件的數(shù)據(jù)列表中欧宜。Odoo會通過文件擴(kuò)展名來確定其文件類型坐榆。CSV文件的一個(gè)特別之處在于它必須匹配所導(dǎo)入的模型名稱,本例冗茸,該模型為 ir.model.access猛拴。第一行應(yīng)為精確匹配模型字段名稱的列名的頭部。

對于標(biāo)量值蚀狰,你可以使用帶引號(因字符串自身包含引號或逗號而需要帶上引號)或不帶引號的字符串愉昆。

在通過CSV文件編寫many2one字段時(shí),Odoo首先嘗試將字段值解釋為XML ID麻蹋。如無點(diǎn)號跛溉,Odoo會將當(dāng)前模塊名添加為命名空間,并在 ir.model.data中查找結(jié)果。如若失敗芳室,會使用字段值來作為參數(shù)調(diào)用模型的name_search函數(shù)专肪,獲取第一條返回的結(jié)果。如依然失敗堪侯,該行被視為無效嚎尤,Odoo拋出錯(cuò)誤。

??注意從CSV中所讀取的數(shù)據(jù)保持為noupdate=False伍宦,并且沒有快捷的修改方式芽死。這表示所有后續(xù)的插件更新會一直重寫由用戶所做的修改。

如果你需要要加載大量的數(shù)據(jù)并且noupdate對你來說不是問題次洼,可以在init鉤子中加載CSV文件关贵。

擴(kuò)展知識...

也可通過CSV文件來導(dǎo)入one2many和many2many字段,但會有些麻煩卖毁。通過揖曾,最好是分別創(chuàng)建記錄然后在XML文件中設(shè)置關(guān)聯(lián),或者通過另一個(gè)CSV文件來設(shè)置關(guān)聯(lián)亥啦。

如果你確需在同一個(gè)文件中創(chuàng)建關(guān)聯(lián)記錄炭剪,對數(shù)據(jù)列進(jìn)行排序來讓標(biāo)量字段居左、關(guān)聯(lián)模型字段居右翔脱,列頭包含待關(guān)聯(lián)名稱和關(guān)聯(lián)模型字段念祭,由逗號分隔:

"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"

這會創(chuàng)建一個(gè)名為my group的組,你可以通過在組記錄的右側(cè)添加列來寫入更多的字段碍侦。如果需要關(guān)聯(lián)多條記錄,重復(fù)該行并修改右側(cè)列為對應(yīng)值隶糕。因Odoo會為空列填寫前一行的值瓷产,你無需拷貝所有數(shù)據(jù),只需在添加行中為值留空來獲取所要填入的關(guān)聯(lián)模型枚驻。
對于x2m字段濒旦,只需要列出要關(guān)聯(lián)記錄的XML ID。

插件更新和數(shù)據(jù)遷移

在編寫插件模塊時(shí)所選擇的數(shù)據(jù)模型可能會存在一些問題再登,因此會需要在插件模塊的生命周期內(nèi)對其進(jìn)行調(diào)整尔邓。為允許這一操作而又無需過多技巧,Odoo支持插件模塊中使用版本號并在需要時(shí)執(zhí)行遷移锉矢。

如何操作...

我們假定在模塊的早前版本中date_release字段是一個(gè)字符字段梯嗽,人們可以填寫任意他們認(rèn)為符合日期的字段。現(xiàn)在我們意識到我們需要對這一字段進(jìn)行比較和累加沽损,因此需要將它的類型修改為Date灯节。Odoo在類型轉(zhuǎn)換上做了很大的優(yōu)化,但在這種情況下得靠我們自己了,因此我們需要給出指令來對已安裝在數(shù)據(jù)庫中的早前版本進(jìn)行轉(zhuǎn)換來讓當(dāng)前版本可以運(yùn)行:

  1. 提升manifest.py文件中的版本號:
'version': '12.0.1.0.1',
  1. 在migrations/12.0.1.0.1/pre-migrate.py中提供預(yù)遷移代碼:
def migrate(cr, version):
     cr.execute('ALTER TABLE library_book RENAME COLUMN date_release TO date_release_char')
  1. 在migrations/12.0.1.0.1/postmigrate.py中添加一個(gè)遷移后代碼:
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)
            else:
              # try some separators, play with day/month/year
              # order ...
              pass
        if new_date:
          cr.execute('UPDATE library_book SET date_release=%s', (new_date,))

沒有這代碼炎疆,Odoo會將原來的date_release列重命名為date_release_moved并新建一列卡骂,因?yàn)闆]有字符字段對日期字段的直接自動轉(zhuǎn)換。從用戶的角度看形入,date_release的數(shù)據(jù)會消失全跨。

運(yùn)行原理...

第一個(gè)重要的點(diǎn)是在插件中增添版本編號,因?yàn)檫w移僅在不同版本中進(jìn)行亿遂。在每次更新期間浓若,Odoo在更新時(shí)將聲明文件中的版本號寫入到ir_module_module表中。版本號前綴使用Odoo的大版本和小版本號崩掘,這是一種良好實(shí)踐七嫌,但1.0.1也可以達(dá)到同樣的效果,因?yàn)樵趦?nèi)部苞慢,Odoo會為短版本號添加其大版本和小版本號诵原。通常,使用長標(biāo)記是一種不錯(cuò)的做法挽放,因?yàn)楹苋菀椎乜闯鏊轻槍doo的哪一個(gè)版本的绍赛。

兩個(gè)遷移文件是無需在任何地方注冊的代碼文件。在更新插件時(shí)辑畦,Odoo對比在ir_module_module中記錄的插件聲明文件中所添加的版本號吗蚌。如果聲明文件的版本號更高(在添加了 Odoo 的大版本和小版本之扣),這一插件的遷移文件夾會被搜索來查看它是否包含帶有范圍內(nèi)版本號的文件夾纯出,以及包含當(dāng)前更新的版本蚯妇。

然后,在查找到的文件夾內(nèi)暂筝,Odoo搜索以pre-開頭的Python文件箩言,加載它們,并預(yù)設(shè)其中定義了名為migrate的函數(shù)焕襟,該函數(shù)有兩個(gè)參數(shù)陨收。此函數(shù)調(diào)用時(shí)以數(shù)據(jù)庫游標(biāo)作為第一個(gè)參數(shù)以及當(dāng)前安裝的版本號作為第二參數(shù)。發(fā)生時(shí)間在Odoo查找插件定義了其它代碼之前鸵赖,因此你可以假定你的數(shù)據(jù)庫布局對比此前版本沒有做過任何修改务漩。

在所有預(yù)遷移函數(shù)成功調(diào)用之后,Odoo加載模型以及插件中所定義的數(shù)據(jù)它褪,這會導(dǎo)致數(shù)據(jù)庫布局的變化饵骨。例如我們在pre-migrate.py文件中重命名了date_release,Odoo會以正確的數(shù)據(jù)類型使用該名稱新建一列茫打。

此后宏悦,通過同樣的搜索算法镐确,會搜索遷移后文件并在找到時(shí)進(jìn)行執(zhí)行。在我們的例子中饼煞,我們需要所有的值來了解我們是否能借助它讓一些數(shù)據(jù)可以使用源葫,否則我們會保持?jǐn)?shù)據(jù)為NULL。除非絕對必要不要編寫遍歷整表的腳本砖瞧,在這種情況下息堂,我們可能會編寫一個(gè)大而不可讀的SQL的switch語句。

小貼士:如果你僅僅是想要重命名一列块促,則無需編寫遷移腳本荣堰。在這種情況下,你可以設(shè)置需修改的字段原列名為oldname參數(shù)竭翠,然后Odoo自己處理重命名振坚。

擴(kuò)展知識...

在預(yù)遷移和遷移后的步驟中,僅能訪問到游標(biāo)斋扰,如果你習(xí)慣于使用Odoo環(huán)境則不是很方便渡八。它可能支導(dǎo)致在這一階段使用模型預(yù)期外的結(jié)果,因?yàn)樵陬A(yù)遷移步驟中,插件模型尚未被載入,同時(shí)也糊,在后遷移步驟中,定義依賴當(dāng)前插件的插件模型也還未被加載逮壁。但是,如果這對于你來說不是問題粮宛,可能是因?yàn)槟阆胍褂媚愕牟寮簧婕暗哪P突蛘呤悄阋阎@不會是一個(gè)問題的模型窥淆,那么你可以編寫如下代碼創(chuàng)建一個(gè)習(xí)慣的環(huán)境:

from odoo import api, SUPERUSER_ID

def migrate(cr, version):
  env = api.Environment(cr, SUPERUSER_ID, {})
  # env holds all currently loaded models

其它內(nèi)容

在編寫遷移腳本時(shí),你常常會碰到重復(fù)的任務(wù)巍杈,比如查某數(shù)據(jù)列或數(shù)據(jù)表是否存在忧饭、重命名或映射一些舊的值到新值。重復(fù)造輪子可能會容易產(chǎn)生問題并讓你沮喪秉氧,如果你可以承擔(dān)額外依賴的話考慮使用https://github.com/OCA/openupgradelib

從XML文件中刪除記錄

在前一節(jié)中蜒秤,我們學(xué)習(xí)了如何通過XML文件創(chuàng)建或更新記錄汁咏。有時(shí),通過依賴的模塊作媚,你會想要刪除此前創(chuàng)建的記錄攘滩。這可以通過<delete>標(biāo)簽實(shí)現(xiàn)。

準(zhǔn)備工作

在這一節(jié)中纸泡,我們將通過XML文件添加一些分類漂问,然后刪除它們。在真實(shí)場景中,你會從另一個(gè)模塊中創(chuàng)建這一記錄蚤假。但為進(jìn)行簡化栏饮,我們將在相同的 XML 文件中添加一些分類,如下:


  <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文件中刪除記錄:

  • 通過此前創(chuàng)建的 XML ID:
<delete model="library.book.category" id="book_category_to_delete"/>
  • 通過搜索域:
<delete model="library.book.category" search="[('name', 'ilike', 'Test')]"/>

運(yùn)行原理...

你將需要使用<delete>標(biāo)簽磷仰。要從模型中刪除記錄袍嬉,需要在model屬性中提供模型的名稱。這是一個(gè)必填的屬性灶平。

在第一個(gè)方法中伺通,你需要提供此前從另一個(gè)模塊數(shù)據(jù)文件創(chuàng)建的記錄的XML ID。在模塊的安裝過程中逢享,Odoo會嘗試查找該記錄罐监。如果以給定XML ID,查找到記錄,它會刪除該記錄瞒爬,否則會報(bào)出一個(gè)錯(cuò)誤弓柱。你可以僅刪除通過XML文件創(chuàng)建的記錄(或帶有XML ID的記錄)。

在第二個(gè)方法中疮鲫,你需要在domain屬性中傳遞域吆你。在模塊的安裝過程中,Odoo會通過這一哉搜索記錄俊犯。如果查找到記錄妇多,則進(jìn)行刪除。如果給定域沒有匹配到任何記錄的話該選項(xiàng)不會拋出異常燕侠。使用該選項(xiàng)時(shí)要極其小心者祖,因?yàn)樗阉鬟x項(xiàng)會刪除所有匹配域的記錄,而導(dǎo)致它會刪除用戶的數(shù)據(jù)绢彤。

??在Odoo很少使用<delete>七问,因?yàn)樗芪kU(xiǎn)。如果使用不慎茫舶,可能會導(dǎo)致系統(tǒng)崩潰械巡。盡可能避免使用它。

從XML文件中調(diào)用函數(shù)

你可以通過XML文件創(chuàng)建所有類型的記錄饶氏,但有時(shí)生成包含一些業(yè)務(wù)邏輯的數(shù)據(jù)會很困難讥耗。你可能會想要在用戶在生產(chǎn)環(huán)境中安裝依賴模塊時(shí)修改記錄。例如疹启,假設(shè)你想要創(chuàng)建一個(gè)模塊來在線展示書籍古程。my_library模塊已有圖片封面字段。設(shè)想在新的模塊中你實(shí)現(xiàn)了減小圖像大小以及在新的縮略圖字段中存儲它的邏輯『把拢現(xiàn)在每當(dāng)用戶安裝這一模塊時(shí)挣磨,可能已有有書和圖像了雇逞。不太可能在XML文件中通過<record>標(biāo)簽生成縮略圖。在這種情況下茁裙,你可以通過<function>標(biāo)簽調(diào)用該模型方法塘砸。

如何操作...

對于這一節(jié),我們將使用前一節(jié)的代碼呜达。作為示例谣蠢,我們將已有圖書價(jià)格增加$10 USD。注意你可能根據(jù)公司配置使用其它幣種查近。

如下步驟會通過XML文件喚醒Python方法:

  1. 在library.book模型中添加_update_book_price()方法:
@api.model
    def _update_book_price(self):
      all_books = self.search([])
      for book in all_books:
        book.cost_price += 10
  1. 在數(shù)據(jù)XML文件中添加<function>:
<function model="library.book" name="_update_book_price"/>

運(yùn)行原理...

在第一步中眉踱,我們添加了update_book_price()方法,它搜索所有圖書并將它們的價(jià)格增加$10 USD霜威。我們在方法名前加上下劃線谈喳,是因?yàn)樗籓RM視作私有,不允許通過RPC調(diào)用戈泼。

在第二步中婿禽,我們使用了<function>標(biāo)簽并添加了兩個(gè)屬性:

  • model:在其中聲明方法的模型名稱
  • name:你想要調(diào)用的方法名

在你安裝這一模塊時(shí),_update_book_price()會被調(diào)用并且書籍的價(jià)格會被加上$10大猛。

??保持為一函數(shù)添加noupdate選項(xiàng)扭倾。否則,會在每次更新模塊時(shí)調(diào)用它挽绩。

擴(kuò)展知識...

通過<function>可以向函數(shù)發(fā)送參數(shù)膛壹。假設(shè)你只想要在某個(gè)分類中增加圖書的價(jià)格并且通過參數(shù)發(fā)送這一增加的值。

那么唉堪,需要創(chuàng)建一個(gè)方法來接收分類作為一個(gè)參數(shù)模聋,如下:

@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

傳遞分類和數(shù)值作為參數(shù),需要使用eval屬性唠亚,如下:

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

在你安裝這一模塊時(shí)链方,會對指定分類的圖書單價(jià)增加$20。.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灶搜,一起剝皮案震驚了整個(gè)濱河市祟蚀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌割卖,老刑警劉巖前酿,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異究珊,居然都是意外死亡薪者,警方通過查閱死者的電腦和手機(jī)纵苛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門剿涮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來言津,“玉大人,你說我怎么就攤上這事取试⌒郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵瞬浓,是天一觀的道長初婆。 經(jīng)常有香客問我,道長猿棉,這世上最難降的妖魔是什么磅叛? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮萨赁,結(jié)果婚禮上弊琴,老公的妹妹穿的比我還像新娘。我一直安慰自己杖爽,他們只是感情好敲董,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著慰安,像睡著了一般腋寨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上化焕,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天萄窜,我揣著相機(jī)與錄音,去河邊找鬼锣杂。 笑死脂倦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的元莫。 我是一名探鬼主播赖阻,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼踱蠢!你這毒婦竟也來了火欧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤茎截,失蹤者是張志新(化名)和其女友劉穎苇侵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體企锌,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榆浓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撕攒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陡鹃。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烘浦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萍鲸,到底是詐尸還是另有隱情闷叉,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布脊阴,位于F島的核電站握侧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嘿期。R本人自食惡果不足惜品擎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望备徐。 院中可真熱鬧孽查,春花似錦、人聲如沸坦喘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓣铣。三九已至答朋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棠笑,已是汗流浹背梦碗。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蓖救,地道東北人洪规。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像循捺,于是被迫代替她去往敵國和親斩例。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355