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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...