odoo 開發入門教程系列-繼承(Inheritance)

来源:https://www.cnblogs.com/shouke/archive/2023/04/14/17253422.html
-Advertisement-
Play Games

繼承(Inheritance) Odoo的一個強大方面是它的模塊化。模塊專用於業務需求,但模塊也可以相互交互。這對於擴展現有模塊的功能非常有用。例如,在我們的房地產場景中,我們希望在常規用戶視圖中直接顯示銷售人員的財產列表。 在介紹特定的Odoo模塊繼承之前,讓我們看看如何更改標準CRUD(創建、檢 ...


繼承(Inheritance)

Odoo的一個強大方面是它的模塊化。模塊專用於業務需求,但模塊也可以相互交互。這對於擴展現有模塊的功能非常有用。例如,在我們的房地產場景中,我們希望在常規用戶視圖中直接顯示銷售人員的財產列表。

在介紹特定的Odoo模塊繼承之前,讓我們看看如何更改標準CRUD(創建、檢索,更新或刪除)方法的行為

Python繼承(Python Inheritance)

目標:

在我們的房地產模塊中,我們從不需要開發任何特定的東西來執行標準的CRUD操作。Odoo框架提供了實現這些操作的必要工具。事實上,多虧經典的Python繼承,我們的模型中已經包含了這樣的操作:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test.model"
    _description = "Test Model"

    ...

我們的 TestModel 類繼承與Model,該Model類提供了 create(), read(), write()unlink()方法。

這些方法(和其它在Model中定義的任何方法)可被擴展以添加指定業務邏輯:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test.model"
    _description = "Test Model"

    ...

    @api.model
    def create(self, vals):
        # Do some business logic, modify vals...
        ...
        # Then call super to execute the parent method
        return super().create(vals)

model()裝飾器對於create() 方法來說是必需的,因為結果集self的內容和創建(creation)的上下文無關,但該裝飾器對於其它CRUD方法來說不是必需的。

Python 3中, super() 等價於 super(TestModel, self)。當你需要使用一條被修改後的結果集調用父方法時,可能需要使用後者。

危險提示

  • 總是調用 super()以避免中斷流非常重要。只有少數非常特殊的情況才無需調用它。
  • 總是返回和父方法一致的數據。例如父方法返回一個dict(),你重寫父方法時也要返回一個dict()

練習--添加業務邏輯到CRUD方法

  • 如果房產記錄狀態不是NewCanceled,則不讓刪除

提示:重寫unlink() ,並記住self可以是一個包含多條記錄的結果集。

  • 創建報價時,設置房產狀態為‘Offer Received’,如果用戶試圖以低於已存在報價的金額創建報價時拋出錯誤。

提示: 可在vals中獲取property_id 欄位,但是它是一個int型。要實例化一個estate.property 對象,請使用self.env[model_name].browse(value) (示例)

    @api.model
    def create(self, vals):
        self.env['gamification.badge'].browse(vals['badge_id']).check_granting()
        return super(BadgeUser, self).create(vals)

修改odoo14\custom\estate\views\estate_property_views.xml 去掉estate_property_view_tree<tree>元素的editable="top"屬性(說明:為了方便執行報價創建操作)

修改odoo14\custom\estate\models\estate_property.py

    @api.constrains('selling_price', 'expected_price')
    def _check_selling_price(self):
        # if record.selling_price < self.expected_price * 0.9:
        #     raise ValidationError("selling price can`t not lower then 90 percent of expected price")
        pass

說明:為了方便實踐操作,暫且不做售價校驗

最末尾新增以下代碼

    def unlink(self):
        for record in self:
            if record.state not in ['New', 'Canceled']:
                raise UserError('can`t delete property which status is New or Canceled')
        return super().unlink()

修改odoo14\custom\estate\models\estate_property_offer.py,導入UserError

from odoo.exceptions import UserError

最末尾添加一下代碼

    @api.model
    def create(self, vals):
        property = self.env['estate.property'].browse(vals['property_id'])
        
        if vals.get('price') < property.best_price:
            raise  UserError('不能低於現有報價')
        property.state = 'Offer Received'
        return super().create(vals)

重啟服務,刷新瀏覽器驗證

刪除非NewCanceled狀態的房產,提示如下:

模塊繼承(Model Inheritance)

引用: 查看主題相關文檔繼承和擴展

我們希望在“Settings/Users & Companies/Users”表單視圖中直接顯示與銷售人員關聯的房產列表。為此,我們需要向res.users模型添加一個欄位,並調整其視圖以顯示它。

Odoo提供了兩種繼承機制來以模塊化的方式擴展現有模型。

第一繼承機制允許模塊通過以下方式修改在另一個模塊中定義的模型的行為:

  • 向模型添加欄位

  • 覆蓋模型中欄位的定義

  • 給模型添加約束

  • 給模型添加方法

  • 重寫模型中的現有方法

第二種繼承機制(委托)允許將模型的每個記錄鏈接到父模型的記錄,並提供對該父記錄的欄位的透明訪問。

odoo中,第一種機制最常用。在我們的例子中,我們希望向現有模型添加一個欄位,這意味著我們將使用第一種機制。例如:

from odoo import fields, models

class InheritedModel(models.Model):
    _inherit = "inherited.model"

    new_field = fields.Char(string="New Field")

這裡可以找到將兩個欄位添加到模型中的示例

class AccountMoveLine(models.Model):
    _inherit = 'account.move.line'

    vehicle_id = fields.Many2one('fleet.vehicle', string='Vehicle')
    need_vehicle = fields.Boolean(compute='_compute_need_vehicle',
        help="Technical field to decide whether the vehicle_id field is editable")

    def _compute_need_vehicle(self):
        self.need_vehicle = False

按照慣例,每個繼承的模型都在其自己的Python文件中定義。在我們的示例中為“models/inherited_model.py”。

練習--添加欄位到用戶模型

  • 添加一下欄位到res.users:
Field Type
property_ids One2many inverse of salesman_id to estate.property
  • 添加一個domain到該欄位,這樣以便僅顯示可獲取房產。

新增odoo14\custom\estate\models\estate_res_user.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from odoo import models, fields

class EstateResUser(models.Model):
    _inherit = 'res.users'

    property_ids = fields.One2many('estate.property', 'salesman_id', domain="[('salesman_id', '=', active_id)]")

修改odoo14\custom\estate\models\__init__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from . import estate_property_type
from . import estate_property_tag
from . import estate_property_offer
from . import estate_property
from . import estate_res_user # 本次新增

視圖繼承(View Inheritance)

參考: 主題關聯文檔可查看Inheritance.

目標: 在用戶表單視圖中顯示與銷售人員關聯的avaliable房產列表其用戶表單視圖

Odoo提供了視圖繼承,其中子“擴展”視圖應用於根視圖之上,而不是就地修改現有視圖(通過重寫它們)。這些擴展既可以添加內容,也可以從父視圖中刪除內容。

擴展視圖使用inherit_id欄位引用其父視圖。它的arch欄位包含多個xpath元素,用於選擇和更改父視圖的內容,而不是單個視圖:

<record id="inherited_model_view_form" model="ir.ui.view">
    <field name="name">inherited.model.form.inherit.test</field>
    <field name="model">inherited.model</field>
    <field name="inherit_id" ref="inherited.inherited_model_view_form"/>
    <field name="arch" type="xml">
        <!-- find field description and add the field
             new_field after it -->
        <xpath expr="//field[@name='description']" position="after">
          <field name="new_field"/>
        </xpath>
    </field>
</record>
  • expr

    一個用於選擇父視圖中單個元素的XPath表達式。如果不匹配任何元素或者匹配多個元素,則拋出錯誤

  • position

    應用於匹配元素的操作:

    inside

    xpath的主體附加到匹配元素的末尾(個人理解,添加為匹配元素的子元素)

    replace

    將匹配元素替換為xpath的主體,將新主體中出現的任何$0節點替換為原始元素

    before

    在匹配元素之前插入xpath的主體作為同級元素

    after

    在匹配的元素之後插入xpaths的主體,作為同級元素

    attributes

    使用xpath主體中的特定屬性元素更改匹配元素的屬性

當匹配單個元素時,可以直接在要查找的元素上設置position屬性。以下兩種繼承都有相同的結果

<xpath expr="//field[@name='description']" position="after">
    <field name="idea_ids" />
</xpath>

<field name="description" position="after">
    <field name="idea_ids" />
</field>

這裡可以找到視圖繼承擴展的示例

<?xml version='1.0' encoding='utf-8'?>
<odoo>
    <record id="view_move_form" model="ir.ui.view">
        <field name="name">account.move.form</field>
        <field name="model">account.move</field>
        <field name="inherit_id" ref="account.view_move_form"/>
        <field name="arch" type="xml">
            <xpath expr="//field[@name='line_ids']//field[@name='account_id']" position="after">
                <field name='need_vehicle' invisible='1'/>
                <field name='vehicle_id' attrs="{'required': [('need_vehicle', '=', True), ('parent.move_type', '=', 'in_invoice')], 'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}" optional='hidden'/>
            </xpath>
            <xpath expr="//field[@name='invoice_line_ids']//field[@name='account_id']" position="after">
                <field name='need_vehicle' invisible='1'/>
                <field name='vehicle_id' attrs="{'required': [('need_vehicle', '=', True), ('parent.move_type', '=', 'in_invoice')], 'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}" optional='hidden'/>
            </xpath>
        </field>
    </record>
</odoo>

練習--添加欄位到用戶視圖

添加property_ids欄位到 base.view_users_form 中新建的notebook

提示: 可以在 這裡找到繼承用戶視圖的示例。

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>

    <record id="res_users_view_form" model="ir.ui.view">
        <field name="name">res.users.view.form.inherit.gamification</field>
        <field name="model">res.users</field>
        <field name="inherit_id" ref="base.view_users_form"/>
        <field name="arch" type="xml">
            <group name="messaging" position="inside">
                <field name="karma"/>
            </group>
        </field>
    </record>

</data>
</odoo>

新增odoo14\custom\estate\views\estate_res_users_views.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
    <record id="estate_res_users_view_form" model="ir.ui.view">
        <field name="name">estate.res.users.view.form</field>
        <field name="model">res.users</field>
        <field name="inherit_id" ref="base.view_users_form"/>
        <field name="arch" type="xml">
            <xpath expr="//page[@name='references']" position="after">
                <page string="Real Estate Properties" name="RealEstateProperties">
                    <field name='property_ids'/>
                </page>
            </xpath>
        </field>
    </record>
</data>
</odoo>

修改odoo14\custom\estate\__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':['security/ir.model.access.csv',
            'views/estate_property_views.xml',
            'views/estate_property_type_views.xml',
            'views/estate_property_tag_views.xml',
            'views/estate_property_offer_views.xml',
            'views/estate_menus.xml',
            'views/estate_res_users_views.xml' # 本次新增
            ]
}

重啟服務,驗證效果

作者:授客
微信/QQ:1033553122
全國軟體測試QQ交流群:7156436

Git地址:https://gitee.com/ishouke
友情提示:限於時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額隨意,您的支持將是我繼續創作的源動力,打賞後如有任何疑問,請聯繫我!!!
           微信打賞                        支付寶打賞                  全國軟體測試交流QQ群  
              


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 和女朋友坐一塊的時候,突然想到了,哈哈哈哈哈 不會很難!!! import java.util.*; import java.lang.Math; // 註意類名必須為 Main, 不要有任何 package xxx 信息 public class Main { public static void ...
  • Flask-SQLAlchemy MySQL是免費開源軟體,大家可以自行搜索其官網(https://www.MySQL.com/downloads/) 測試MySQL是否安裝成功 在所有程式中,找到MySQL→MySQL Server 5.6下麵的命令行工具,然後單擊輸入密碼後回車,就可以知道MyS ...
  • 前言 在上一篇文章中,我們介紹了~運算符的高級用法,本篇文章,我們將介紹<< 運算符的一些高級用法。 一、人物簡介 第一位閃亮登場,有請今後會一直教我們C語言的老師 —— 自在。 第二位上場的是和我們一起學習的小白程式猿 —— 逍遙。 二、計算2的整數次冪 代碼示例 #include <stdio. ...
  • 布隆過濾器是一個精巧而且經典的數據結構。 你可能沒想到: RocketMQ、 Hbase 、Cassandra 、LevelDB 、RocksDB 這些知名項目中都有布隆過濾器的身影。 對於後端程式員來講,學習和理解布隆過濾器有很大的必要性。來吧,我們一起品味布隆過濾器的設計之美。 1 緩存穿透 我 ...
  • Java + Jpcap實現監控 IP包流量 說明:本設計是電腦網路課程的課設,因為代碼是提前實現的,本博客於後期補上,又因為代碼沒寫註釋自己也看不懂了,所以,僅供參考,就當提供一種實現方式。 文中提供的《Jpcap中文API文檔》來源於網路,本文僅用於學習交流,如有侵權,可聯繫我進行刪除。 效果 ...
  • 是什麼 迴圈隊列, FIFO先進先出 怎麼用 初始化 //C11 deque<int> deq{1,2,3,4,5}; //拷貝構造,可以拷貝deque queue<int> que(deq); //100個5 queue<int> que2(100,5); //運算符重載 que2 = que; ...
  • 集合的理解和好處 數組一旦定義,長度即固定,不能修改。要添加新元素需要新建數組,然後迴圈拷貝,非常麻煩 集合可以動態保存任意多個對象,使用比較方便 提供餓了一系列方便的操作對象的方法:add、remove、set、get等 使用集合添加、刪除新元素的示意代碼,簡潔明瞭 集合主要是兩組(單列集合,雙列 ...
  • 本文已經收錄到Github倉庫,該倉庫包含電腦基礎、Java基礎、多線程、JVM、資料庫、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分散式、微服務、設計模式、架構、校招社招分享等核心知識點,歡迎star~ Github地址 如果訪問不了Github,可以訪 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...