第二章 Odoo开发之模块继承

文章目录

一、模型继承

 1、模块继承前的准备工作

 1.1 同级目录下创建store_member目录作为school_store的扩展模块

1.2 在根目录下的__manifest__.py文件中指明依赖模块 

2、经典继承

2.1 继承父类模型的方法

 2.2 使用修改的方式来继承父类的视图

3、原型继承

4、代理继承

5、mixin类

5.1 对模型添加消息聊天窗口和计划活动

 二、视图和数据继承 

1、视图继承

1.1 使用XPath选取继承点

 1.2 xpath语法规则

2、数据继承

 三、网页继承

1、继承网页控制器

2、继承QWeb模板


 在Odoo中,继承是一种重要的开发概念,它允许你修改或扩展现有模型(Model)、视图(View)或控制器(Controller)而无需修改原始代码。

  • 修改现有模型的行为: 通过继承现有模型,你可以修改模型的方法、添加新字段、更改默认值等,而无需修改原始模型的代码。这使得在不破坏现有功能的情况下进行定制变得更加容易。 
  • 添加新字段: 继承可以用于在现有模型中添加新的字段。这使得你能够将自定义数据集成到标准模型中,以满足特定需求。
  • 修改视图: 通过继承现有视图,你可以修改视图的结构、添加新的元素,或者重定义现有元素的行为。这使得你能够调整用户界面以满足定制需求。
  • 重载控制器方法: 在Odoo中,你可以通过继承控制器并重载其方法来修改现有业务逻辑。这使得你能够自定义处理特定请求的方式。

一、模型继承

 1、模块继承前的准备工作

 1.1 同级目录下创建store_member目录作为school_store的扩展模块

        使用scaffold 来快速创建目录骨架

         odoo scaffold <module_name> <path_to_target_dir>

1.2 在根目录下的__manifest__.py文件中指明依赖模块 

         使用depends来指明依赖模块

{
    'name':'Store Members',
    'description':'是否为可用',
    'author':'lizewen',
    'depends':['school_store'],
    'application':False,
    'data': [],
}

2、经典继承

只使用 _inherit 属性,可对模型执行有效的更改。

可以看作是在父类模型中插入了一个扩展。

from odoo import fields,models

class Member(models.Model):
    _inherit='school.store'
    is_available=fields.Boolean('Is Available?')

2.1 继承父类模型的方法

        继承模型时,可对已有字段做出增量修改。也就是只需要定义要修改或添加的属性。

        在继承类中继承方法,我们要使用相同方法名重新定义该方法。

        使用super()来调用父类已实现的方法

 在这个列子中,调用了父类的_check_mem()方法

super()._check_mem()

 self.ensure_one()方法介绍:

        用于确保当前对象集合只包含一个记录的方法。这个方法通常在Odoo的模型(Model)中的方法中使用,主要用于执行一些需要确保只有一个记录存在的操作。

主要应用场景:

  • 检索唯一记录: 当一个方法需要检索模型中的唯一一条记录时,可以使用 self.ensure_one()。如果存在多条记录,将引发异常。
def get_unique_record(self):
    self.ensure_one()
    # 执行获取唯一记录的操作
  •  执行唯一记录的操作: 当一个方法执行的操作只适用于唯一一条记录时,可以使用 self.ensure_one() 来确保只有一个记录存在
def process_unique_record(self):
    self.ensure_one()
    # 执行仅适用于唯一记录的操作
  •  验证唯一性: 在一些情况下,需要验证某些字段的唯一性,确保不会存在重复值。在这种情况下,可以使用 self.ensure_one() 来确保只有一个记录存在
@api.constrains('field_name')
def _check_unique_field(self):
    self.ensure_one()
    # 执行验证唯一字段的逻辑

 2.2 使用修改的方式来继承父类的视图

        inherit_id属性来引用所要继承 的视图。

        通过ref属性指向视图 的外部标识符定位所继承的视图。

        使用position=”after”来声明位置。

 具体实现模板:

    ref:这里需要填写视图的ID

    视图ID如何查看:技术-用户界面-视图

     在after后面的也就是修改的字段,在模型中被定义的字段

<odoo>
    <record id="view_form_book_extend" model='ir.ui.view'>
        <field name="name">经典继承之视图继承</field>
        <field name="model">school.store</field>
        <field name="inherit_id" ref="这里写视图的XMLID" />
        <field name="arch" type="xml">
            <field name="name" position="after">
                <field name="is_available" />
            </field>
        </field>
    </record>
</odoo>

3、原型继承

使用 _inherit 和 _name 属性。

此时你会获得一份继承模型的副本

这个新模型只是有自己的功能以及父类的功能,并且自己的功能不会添加到父类中

新模型与父类模型相互独立。

不受父类模型修改的影响。

有自己独立的数据表。

from odoo import fields,models

class Member(models.Model):
    _name = 'store.member'
    _inherit='school.store'
    is_available=fields.Boolean('Is Available?')

4、代理继承

代理继承属于内嵌模型

创建新模型记录也会创建并连接所代理的模型记录

继承模型中不存在的代理字段模型可进行读写操作,类似于关联的计算字段

通过代理机制,嵌套模型的所有字段像父模型字段一样自动可用

代理继承仅用于数据层面,不适用于逻辑层。

没有继承所继承模型的任意方法,但可以使用点号来访问,成为点号标记。

在实际开发中,一般会偏向代理继承,因为不拷贝就可以复用数据结构。

这个例子中在store.member中嵌入了res.partner,在新建记录时,会自动创建一个关联的partner而且通过该字段引用

from odoo import fields,models

class menber(models.Model):
    _name='store.member'
    _description='Store Member'
    partner_id=fields.Many2one(
        'res.partner',
        delegate=True,
        ondelete='cascade',
        required=True)

5、mixin类

 面对多个父类模型继承时,_inherit的值不是单个名字,而是一个模型列表

这可以用于多个模型混合加入一个模型,这样我们可以多次使用同一模型的功能

而mixin类广泛使用了这种模式。

 mixin类像是一种功能的容器,可以复用、实现通用功能,可添加到其他模型中,一般不单独使用

mixin类是基于models.AbstractModel的抽象模型。

在源代码中搜索models.AbstractModel就可以找到。

常用的mixin:

        mail.thread:

                为模型添加了跟踪记录和关注者管理功能,可以在模型中跟踪记录、添加关注者,并发送电子邮件通知给关注者。

        mail.activity.mixin 

                 该 Mixin 为模型添加了待办事项功能,可以在模型中创建、更新和完成待办事项,并发送电子邮件通知给相关用户。

        website.published.mixin

                该 Mixin 为模型添加了网站发布功能,可以在网站上发布模型记录,并提供 SEO 和社交分享功能。

        sale.order.line.make.procurement.mixin

                该 Mixin 为销售订单行添加了自动生成采购需求的功能,可以在销售订单行中创建与其相关的采购需求。

        product.template.sale.mixin

                该 Mixin 为产品模板添加了销售信息,可以在产品模板中定义销售价格、定价策略和相关产品等。

5.1 对模型添加消息聊天窗口和计划活动

步骤:

  • 添加提供mixin的插件模型依赖,即mail

                在__manifest__.py 文件添加对mail插件的依赖

"depends":["mail"],
  • 继承mail.thread和mail.activity.mixin这两个mixin类

                在模型文件中继承mixin类

class Member(models.Model):
    _name ='store.member'
    _description ='Store Member'
    _inherit =["mail.thread","mail.activity.mixin"]
  • 在表单视图中添加字段
<odoo>
    <record id="view_form_member" model="ir.ui.view">
        <field name="name">Store Member Form View </field>
        <field name="model">store.member</field>
        <field name="arch" type="xml">
            <form>
                <header>
                </header>
                <sheet>            
                <group>
                    <group>
                    </group>
                </group> 
                </sheet> 
                <!-- mail mixin -->
                <div class="oe_chatter">
                    <field name="message_follower_ids" widget="mail_followers" />
                    <field name="activity_ids" widget="mail_activity" />  
                    <field name="message_ids" widget="mail_thread" />
                </div>                    
            </form>
        </field>
    </record>
</odoo>
<record id="view_sale_order_form_inherit" model="ir.ui.view">
    <field name="name">sale.order.form.inherit</field>
    <field name="model">sale.order</field>
    <field name="inherit_id" ref="sale.view_order_form"/>
    <field name="arch" type="xml">
        <field name="partner_id" position="attributes">
            <attribute name="string">New Partner Label</attribute>
        </field>
    </field>
</record>

                        

 二、视图和数据继承 

1、视图继承

继承视图,我们需要定位到所要继承的节点, 然后声明所做的修改。

除string属性外的任意XML元素和属性均可用于选取继承点使用的节点,字符串属性会在生成视图期间翻译成用户所使用的语言,因此不能作为节点选择器。

position 属性是在视图继承过程中用来指定插入或替换位置的关键属性。position 属性告诉Odoo在目标视图中的哪个位置进行插入、替换或删除元素。它通常与 <field> 标签或其他视图元素一起使用。

用position属性声明继承操作,参数如下:                                          

inside:在所选节点内添加内容,这一节点应是<group>或<page>一类的容器                                  

after:在选定节点之后向父节点添加内容                                            

before:在选定节点之前向父节点添加内容                                            

replace:替换所选节点                                            

attributes:修改匹配元素的属性值 

move:效果是将子定位符目标节点移到父定位符的目标位置

<record id="view_sale_order_form_inherit" model="ir.ui.view">
    <field name="name">sale.order.form.inherit</field>
    <field name="model">sale.order</field>
    <field name="inherit_id" ref="sale.view_order_form"/>
    <field name="arch" type="xml">
        <field name="partner_id" position="attributes">
            <attribute name="string">New Partner Label</attribute>
        </field>
    </field>
</record>

1.1 使用XPath选取继承点

XPath(XML Path Language)是一种用于在XML文档中选择节点的查询语言。在Odoo中,XML视图继承时,XPath常用于选择继承点(被继承的目标)和定义修改的位置。

  • 选择整个视图:

        如果要继承整个视图,可以使用 / 来选择根节点。

<xpath expr="/" position="attributes">
    <!-- Your modifications here -->
</xpath>
  • 选择具体的字段或元素:

        使用 ///path/to/element 来选择具体的字段或元素。

<xpath expr="//field[@name='partner_id']" position="after">
    <!-- Your modifications here -->
</xpath>

        或

<xpath expr="/form/sheet/field[@name='partner_id']" position="after">
    <!-- Your modifications here -->
</xpath>
  •  选择特定位置:

         使用 position 属性来指定插入、替换或删除的位置

<xpath expr="//field[@name='partner_id']" position="after">
    <!-- Your modifications here -->
</xpath>
<xpath expr="//field[@name='amount_untaxed']" position="attributes">
    <!-- Your modifications here -->
</xpath>
<xpath expr="//field[@name='carrier_id']" position="replace">
    <!-- Your modifications here -->
</xpath>

注:

         如果XPath表达式匹配到了多个元素,仅会选取第一个作为扩展目标。所以表达式应越精确 越好,使用唯一属性。name属性最易于确保找到精确元素作为扩展点。因此在创建视图XML元素时添加唯一标识符就非常重要。

 1.2 xpath语法规则

  1. 节点选择:

    • /: 从文档的根节点开始选择节点。
    • //: 选择节点的任意后代节点。
    • .: 选择当前节点。
    • ..: 选择当前节点的父节点。
  2. 节点过滤:

    • [@attribute='value']: 通过属性值过滤节点。
      • 例如://book[@category='fiction'] 选择所有category属性为fictionbook元素。
    • [position()]: 选择具有特定位置的节点。
      • 例如://book[position()=1] 选择文档中第一个book元素。
  3. 通配符:

    • *: 匹配任意元素节点。
    • @*: 匹配任意属性节点。
  4. 轴(Axis):

    • ancestor: 选择所有祖先节点。
    • parent: 选择父节点。
    • child: 选择所有子节点。
    • descendant: 选择所有后代节点。
    • following: 选择当前节点之后的所有节点。
    • preceding: 选择当前节点之前的所有节点。
  5. 运算符:

    • and: 逻辑与。
    • or: 逻辑或。
    • not: 逻辑非。
  6. 位置路径:

    • /path/to/element: 指定节点的路径。
      • 例如:/bookstore/book/title 选择文档中所有bookstore元素下的book元素下的title元素。
  7. 函数:

    • name(): 返回当前节点的名称。
    • text(): 返回当前节点的文本内容。
    • contains(string, substring): 检查一个字符串是否包含另一个字符串。
      • 例如://book[contains(@title, 'XML')] 选择所有title属性中包含字符串'XML'的book元素。
  8. 数字位置:

    • [position()=1]: 选择具有特定位置的节点。
    • [last()]: 选择最后一个节点。

2、数据继承

普通数据记录也可被继承,在实际应用,通常是重写已有值

这时我们只需定位到需写入的记录,以及更新的字段和值。无需使用XPath表达式,因为我们并不是像对视图那样修改XML arch结构。

具体的继承结构为:

<record id="x" model="y">

数据加载元素执行对y模型的插入或更新操作:若不存在记 录x,则创建,否则被更新/覆盖。

 例子:

        对权限组修改名称

<odoo>
<!-- 修改权限组名称 -->
    <record id="school_store.school_store_user" model="res.groups">
        <field name="name">storeAdmin</field>
    </record>
</odoo>

 三、网页继承

1、继承网页控制器

 什么是网页控制器

         网页控制器(Web Controller)是一种用于处理Web请求和生成Web响应的机制。Web控制器允许你创建自定义的Web页面、处理用户输入、执行业务逻辑,并返回渲染后的Web页面或JSON响应。应关注展示逻辑,不处理业务逻辑,业务逻 辑在模型方法中处理。

        最基本的网页控制器示例:

from odoo import http

class MyWebController(http.Controller):

    @http.route('/my/custom/page', auth='public', website=True)
    def my_custom_page(self, **kwargs):
        return http.request.render('my_module.my_template')
  1. MyWebController 类继承自 http.Controller
  2. @http.route 装饰器用于定义Web路由。
    • /my/custom/page: 这是Web页面的URL路径。
    • auth='public': 指定该页面是公开访问的,无需身份验证。
    • website=True: 表示这是一个网站页面。
  3. my_custom_page 方法是处理Web请求的方法。
    • **kwargs: 允许接收任意数量的关键字参数。
    • return http.request.render('my_module.my_template'): 返回一个由模板渲染的Web响应。

如何继承网页控制器:

你需要继承哪个控制器你就需要将其的controllers.main引入

红色部分为默认写法不用动,你只需要将黑色部分换成其模型的文件目录,紫色为所取得名字

from odoo.addons.website_sale.controllers.main import WebsiteSale

from odoo import http
from odoo.addons.website_sale.controllers.main import WebsiteSale

class CustomWebsiteSale(WebsiteSale):

    @http.route(['/shop/custom_page'], type='http', auth="public", website=True)
    def custom_page(self, **kwargs):
        return http.request.render('your_module.custom_template')

注:

        需要在根目录下得__init__.py文件中引入controllers以及models

        需要在controllers的目录下的__init__.py文件中引入main

2、继承QWeb模板

        QWeb(Quick Web)是Odoo中的一种模板引擎,用于在服务器端生成动态的网页内容。QWeb采用类似于XML的语法,并与Odoo的模型、视图、控制器等其他组件深度集成,使得开发者可以方便地创建和管理Web界面。

以下是QWeb的一些主要特点和用法:

XML语法:

  • QWeb使用XML语法,这种语法旨在使模板易于阅读和理解。
  • 例如:
<div t-if="condition">Content to display if condition is true</div>

模板标签:

  • QWeb引入了一系列模板标签,允许开发者在模板中执行逻辑、迭代、条件渲染等操作。
  • 例如:
<t t-foreach="records" t-as="record">
    <div t-field="record.field_name"/>
</t>

条件渲染:

  • 使用 t-ift-else 可以在模板中实现条件渲染。
  • 例如
<div t-if="condition">Content to display if condition is true</div>
<div t-else>Content to display if condition is false</div>

循环迭代:

  • 使用 t-foreach 可以在模板中对列表或集合进行迭代。
  • 例如:
<t t-foreach="records" t-as="record">
    <div t-field="record.field_name"/>
</t>

动态内容:

  • 使用 t-esc 可以在模板中显示动态计算的内容。
  • 例如:
<p>Hello <t t-esc="user.name"/></p>

模板继承:

  • QWeb支持模板的继承,允许开发者创建一个基础模板,然后在子模板中继承并扩展它。
  • 例如:
<t t-extend="website.layout">
    <t t-append="website.content">
        <!-- Additional content for the website layout -->
    </t>
</t>

与模型字段的集成:

  • QWeb可以与Odoo的模型字段深度集成,通过 t-fieldt-options 等属性直接与模型字段进行交互。
  • 例如:
<input t-field="record.field_name"/>

模板注释:

  • 使用 <!-- ... --> 注释可以在模板中添加注释。
  • 例如:
<!-- This is a comment -->

如何继承QWeb模板

        QWeb继承是一个<template>元素,使用额外inherit_id属性来标识待继承的QWeb模板

<!-- views.xml -->
<template id="view_id" name="View Name" inherit_id="your_module.base_template">
    <t t-extend="your_module.child_template"/>
</template>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dear.爬虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值