zoukankan      html  css  js  c++  java
  • odoo框架之模块继承

    odoo框架之模块继承

    开篇前准备

    # 新建模块 library_member
    # 目录结构
    	library_member
    		- models
    			- __init__.py
    		- views
    		- __init__.py
    		- __manifest__.py
    

    一.原模型继承

    ​ in-place模型继承, _inherit 属性

    # 原模型继承的作用:
    	# 1. 为模型添加字段
        # 2.  修改已有字段
        
    # 继承的结果
    	# 1. 原模型继承,在原模型上添加修改,
        # 2. 重新指定_name属性,生成新的表
    

    为模型添加字段

    # 1.将models导入到library_member/__init__.py文件来
    	from . import models
    # 2.在library_member/models/__init__.py添加如下代码
    	from . import library_book
    # 3.创建library_book.py, 继承 library.book模型,
    	from odoo import fields, models
    	class Book(models.Model):
            # 声明继承,以及要继承的模型
            _inherit = 'library.book' 
            # 添加新的字段
            is_available = fields.Boolean('Is Available?')
    

    修改已有字段

    ​ 继承模型时,可对已有字段叠加修改,也就是说仅需定义要增加或修改的字段属性。

    # 目的:
       #为isbn字段添加一条提示,说明同时支持10位数的 ISBN(稍后会实现该功能)
       #为publisher_id字段添加数据库索引,以提升搜索效率
       
    # 步骤
    	# 1.编辑library_member/models/library_book.py,加入如下代码
        
    class Book(models.Model):
    	...
        # 重新定义isbn字段
        isbn = fields.Char(help="Use a valid ISBN-13 or ISBN-10.")
        # index 是添加索引
        publisher_id = fields.Many2one(index=True) 
    	
    

    二.修改视图和数据

    视图继承

    ​ 表单、列表和搜索视图通过arch XML结构定义.

    ​ 定位到xml元素的位置后,对其进行修改. 视图中也存在inherit_id属性

    <!-- 添加views/book_view.xml文件来继承 Partner 视图  -->
    <?xml version="1.0"?>
    <odoo>
        <record id="view_form_book_extend" model="ir.ui.view">
            <field name="name">Book: add Is Available? field</field>
            <field name="model">library.book</field>
            <field name="inherit_id" ref="library_app.view_form_book" />
            <field name="arch" type="xml">
                <field name="isbn" position="after">
                    <field name="is_available" />
                </field>
            </field>
        </record>
    </odoo>
    

    ​ 注解

    ### 同一个模块下,xml id 不要重复
    # 1.  view_form_book_extend 是当前视图的id
    # 2.  由于没有生成新的模型所以依旧依赖library.book
    # 3.  inherit_id 字段,ref的值是 继承这个视图的xml id
    
    # 4. position 指的是位置
    # 5. is_available 是新增字段
    

    节点定位的方式以及节点的位置

    # 节点位置
        inside(默认值):# 在所选节点内添加内容,这一节点应是<group>或<page>一类的容器
        
    	after:# 在选定节点之后向父节点添加内容
    	
    	before:# 在选定节点之前向父节点添加内容
    	
    	replace:# 替换所选节点。若使用空元素则会删除该元素。Odoo 之后还允许使用其它标记来包裹元素,通过在内容中使用$0来表示被替换的元素。
    	
    	attributes:# 修改匹配元素属性值。内容中应包含带有一个或多个<attribute name=”attr-name”>value</attribute>元素。如<attribute name=”invisible”>True</attribute>,若不带内容,如<attribute name=”invisible” />则 attribute 会从所选元素中删除。
    	
    	replace # 可删除 XML 元素,但应避免这么做。这么做会破坏其它依赖所删除节点、将其作为占位符添加元素的模块。一个替代方案是,让该元素不可见。
        
    	 move #  子元素合并。效果是将子定位符目标节点移到父定位符目录位置。如:<field name="target_field" position="after"><field name="my_field" position="move"/></field>
    
    filed 字段定位节点
    <field name="target_field" position="after">
        	....
    </field>
    
    
    <!-- 当name出现重复时,无法精确定位到节点 -->
    
    xpath 定位节点
    # 使用xpath的原因
    	# 1. 存在没有带唯一值的属性来用作 XML 节点选择器。在所选元素没有 name 属性时可能出现这一情况,如<group>、<notebook>或<page>视图元素。
    
    	# 2. 另外就是有多个带有相同 name 属性的元素,比如在看板 QWeb 视图中相同字段可能在同一 XML 模板中被多次包含。
        
        # 3. xpath也有限制
    
    # 例子:
    <xpath expr="//field[@name='isbn']" position="after">
        <field name="is_available" />
    </xpath>
    

    修改数据

    # 1. 普通数据记录不同于视图,它没有 XML arch 结构,也不能使用 XPath 来进行扩展。但还是可以通过替换字段值来进行修改。
    
    # 2. <record id="x" model="y">数据加载元素实际是对 y 模型进行插入或更新操作。若不存在记录 x,则被创建,否则被更新/覆盖。其它模块中的记录可通过<module>.<identifier>全局标识符访问,因此可以在我们的模块中重写其它模块中已写入的数据
    
    
    <!-- 我们将 User 安全组的名称修改为 Librarian,对应修改library_app.library_group_user记录。添加library_member/security/library_security.xml并加入如下代码: -->
    <odoo>
        <!-- Modify Group name -->
        <record id="library_app.library_group_user" model="res.groups">
            <field name="name">Librarian</field>
        </record>
    </odoo>
    

    三.其他模型继承机制

    原型继承拷贝功能_inherit

    # 即 在继承模型中添加_name属性, 相当于拷贝了一个一模一样的表,添加上新增字段
    # 缺点:
    	# 1.数据结构冗余
    

    代理继承内嵌模型(_inherits)

    ​ 定义: UML 中这种称作组合(composition)关系:父类无需子类即可存在,而子类必须要有父类才能存在。

    ​ 在图书项目中,我们要添加一个图书会员模型。会员有会员卡并通过会员卡借阅读书。我们要记录卡号,还要存储email 和地址这类个人信息。Partner 模型已包含联系和地址信息,所以最好是进行复用,而不去创建重复的数据结构。

    # 为会员模型创建library_member/models/library_member.py文件并加入如下代码:
    from odoo import fields, models
    
    class Member(models.Model):
        _name = 'library.member'
        _description = 'Library Member'
        card_number = fields.Char()
        partner_id = fields.Many2one(
            'res.partner',
            delegate=True, # 复用users的
            ondelete='cascade',
            required=True)
    
    ### 代理继承可通过如下组合来进行替代:
    
    	1.父模型中的一个 many-to-one 字段
    	2.重载 create()方法自动创建并设置父级记录
    	3.父字段中希望暴露的特定字段的关联字段
     # 有时这比完整的代理继承更为合适。例如res.company并没有继承res.partner,但使用到了其中好几个字段。
    
    # 步骤
    # 1. 在library_member/model/__init__.py导入新模型 library_member
    	from . import library_book
    	from . import library_member
        
    # 2.创建library_member/security/ir.model.access.csv
    id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
    access_member_user,Member User Access,model_library_member,library_app.library_group_user,1,1,1,0
    access_member_manager,Member Manager Access,model_library_member,library_app.library_group_manager,1,1,1,1
    
    # 3.创建library_member/views/library_menu.xml
    <odoo>
        <act_window id="action_library_member"
            name="Library Members"
            res_model="library.member"
            view_mode="tree,form" />
        <menuitem id="menu_library_member"
            action="action_library_member"
            parent="library_app.menu_library" />
    </odoo>
    # 4. 创建library_member/views/member_view.xml
    <?xml version="1.0" ?>
    <odoo>
        <record id="view_form_member" model="ir.ui.view">
            <field name="name">Library Member Form View</field>
            <field name="model">library.member</field>
            <field name="arch" type="xml">
                <form>
                    <group>
                        <field name="name" />
                        <field name="email" />
                        <field name="card_number" />
                    </group>
                </form>
            </field>
        </record>
        <record id="view_tree_member" model="ir.ui.view">
            <field name="name">Library Member List View</field>
            <field name="model">library.member</field>
            <field name="arch" type="xml">
                <tree>
                    <field name="name" />
                    <field name="card_number" />
                </tree>
            </field>
        </record>
    </odoo>
    

    使用 mixin类继承模型

    ​ mixin 是基于 models.Abstract 的抽象的模型(而不是models.Model),它在数据库中没有实际的体现,而是提供功能供其它模型复用(混合 mixed in)

    ​ Odoo 插件提供多种 mixin,最常的两种由 Discuss 应用(mail 模块)提供:

    # 1. mail.thread提供在许多文档表单下方或右侧的消息面板功能,以及消息和通知相关逻辑。这在我们自己的模型中将经常会添加,下面就来一起学习下
    
    # 2. mail.activity.mixin模型提供待办任务计划
    
    ### mail 模块现在通过mail.activity.mixin抽象模型提供Activities任务管理功能
    
    # 步骤
    # 1. 'depends': ['library_app', 'mail'], 添加依赖
    # 2. mixin 类的继承通过_inherit属性完成,编辑 library_member.py
    	class Member(models.Model):
        _name = 'library.member'
        _description = 'Library Member'
        _inherit = ['mail.thread', 'mail.activity.mixin']
    # 3. 编辑 member_view.xml ,form内添加
    <form>
    	....
    	<!-- mail mixin fields -->
    	<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>
    

    四.继承方法

    ​ 与python继承相同

    # 在library_member/models/library_book.py文件中添加如下方法:
    from odoo import api, fields, models
    
    class Book(models.Model):
        ...
        
        def _check_isbn(self):
            self.ensure_one()
            isbn = self.isbn.replace('-', '')
            digits = [int(x) for x in isbn if x.isdigit()]
            if len(digits) == 10:
                ponderators = [1, 2, 3, 4, 5, 6, 7, 8, 9]
                total = sum(a * b for a, b in zip(digits[:9], ponderators))
                check = total % 11
                return digits[-1] == check
            else:
            	# 执行父类方法
                return super(Book,self)._check_isbn()
    

    五.继承 Web 控制器和模板

    继承网页控制器

    • 在控制器端添加对查询参数的支持,访问/library/books?available=1过滤出可借阅图书
    • 在模板端,添加一个图书不可用的表示
    from odoo import http
    from odoo.addons.library_app.controllers.main import Books
    
    class BookExtended(Books):
        @http.route()
        def list(self, **kwargs):
            response = super().list(**kwargs)
            if kwargs.get('available'):
                Book = http.request.env['library.book']
                # 新增过滤条件 
                books = Book.search([('is_available', '=', True)])
                response.qcontext['books'] = books
            return response
        
    # 注意:
    	# 它至少需要一个简单的@http.route()装饰器来保持路径活跃。如果不带参数,将会保留父类中定义的路由。但也可以为@http.route() 装饰器添加参数,来重新定义或替换类路由。
    

    继承 QWeb 模板

    ​ 与视图继承类似,定义继承模板,xpath定位节点

    ​ 添加library_member/views/book_list_template.xml文件并加入如下代码:

    <odoo>
        <template id="book_list_extended"
            name="Extended Book List"
            inherit_id="library_app.book_list_template">
            <xpath expr="//span[@t-field='book.publisher_id']" position="after">
                <t t-if="not book.is_available">
                    <b>(Not Available)</b>
                </t>
            </xpath>
        </template>
    </odoo>
    

  • 相关阅读:
    Storm系列(六)架构分析之Scheduler-调度器[EventScheduler]
    Storm系列(五)架构分析之Nimbus启动过程
    Storm系列(四)Topology提交校验过程
    Storm系列(三)Topology提交过程
    Storm系列(二)系统结构及重要概念
    Esper系列(一)初探
    scala学习笔记(四)样本类与模式匹配
    Storm系列(一)集群的安装配置
    Kafka系列(二)特性和常用命令
    Kafka系列(一)安装和配置说明
  • 原文地址:https://www.cnblogs.com/dengz/p/12889136.html
Copyright © 2011-2022 走看看