odoo14 | tree视图增加动态按钮并打开向导视图显示获取数据(无JS辅助实现)

首先展示效果,看一下本篇文章要讲的是什么效果

1.下推列表的tree视图中,选择记录前的样子

2.选择记录后,出现“下推采购单”按钮

3.点击按钮后,弹出向导界面

后续的下推逻辑,把数据在那个模型中创建表单或者有什么其他的操作就都在按钮的方法中写就可以了,本篇在后面讲解的时候仅从从“待下推采购列表”开始,止步于“确认下推采购”按钮之前,本篇教程中所使用的案例项目为个人教程使用的虚拟项目,非真实项目,不涉及商业秘密和源代码泄露等问题

首先介绍一下涉及到的文件结构

 由于该模块中还有其他模型和配套的视图,需要读者提前了解文中提到的技术所需的模型和视图的名称和关系,在后续的代码块前会先说明代码所属文件的相对路径

/models/book_number_keep_list.py

由于本篇中该模型只作为承载,所以只展示基础字段部分就够用了

from odoo import fields, api, models
from odoo.exceptions import UserError


class book_number_keep_list(models.Model):
    _name = 'book.number.keep.list'
    _description = '书籍数量维持列表'

    name = fields.Char('书籍名称', required='1')
    description = fields.Text('书籍介绍')
    book_image = fields.Binary('书籍封面')
    book_money = fields.Float('含税单价')
    book_plans_number = fields.Integer('计划数量')
    book_in_hand_number = fields.Integer('在手数量', readonly='1', default=0)

    book_need_push = fields.Integer(string='总书籍待采购数')

    book_review = fields.Text('书评')

/views/book_number_keep_list_views.xml

它book_number_keep_list.py配套的基础数据表的表单和列表,在此解释是为了避免有人对book_need_push_list.xml文件中的action写法产生疑问

画面简单展示一下
配套的form视图,其中涉及的其他技术点请查看本博客其他文章

/views/book_need_push_list.xml 

这是待下推列表视图,它与book_number_keep_list_views.xml文件中的两个视图共享同一个模型,即同一个基础数据表

<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
    <data>
        <record id="book_need_push_list_tree" model="ir.ui.view">
            <field name="name">待下推采购列表tree</field>
            <field name="model">book.number.keep.list</field>
            <field name="arch" type="xml">
                <tree create="false" delete="false" >
                    <header>
                        <button name="%(book_warehouse_management.xrh_project_wizard_action)d"
                                string="下推采购单" type="action" class="oe_highlight"/>
                    </header>
                    <field name="name"/>
                    <field name="book_money"/>
                    <field name="book_need_push"/>
                </tree>
            </field>
        </record>

        <record id="action_book_need_push_list" model="ir.actions.act_window">
            <field name="name">待下推采购列表</field>
            <field name="res_model">book.number.keep.list</field>
            <field name="view_ids" eval="[(5, 0, 0),
                (0, 0, {'view_mode': 'tree', 'view_id': ref('book_need_push_list_tree')})]"/>
            <field name="domain">[('book_need_push','>', 0)]</field>
        </record>

    </data>
</odoo>

其中的

<header>
    <button name="%(book_warehouse_management.xrh_project_wizard_action)d" string="下推采购单" type="action" class="oe_highlight"/>
</header>

就是为tree视图增加动作按钮,其作用和

是差不多的,都是可以读取出所有被选中的记录的对象

其中的 %(book_warehouse_management.xrh_project_wizard_action)d 是让按钮直接去找后面要说的自己写的向导视图的动作action

同时注意

 按钮类型为活动类型,这里涉及到按钮常用的两个类型,object和action,这里用的是action,关于button相关技术点请移步查看其他文章。

如果这里的type没有使用action而用了object,则会遇到该技术点中的全局第一个报错,在写完这部分后优先检查这里有没有写错。

上面就说完按钮部分了,如果此时还不清楚按钮的name参数怎么写可以先继续看下文,后面我们还会回来讲按钮和向导的数据是怎么联动的。

下面讲向导部分

 向导的瞬态模型和配套视图并不写在model和views中,是单独写在wizard文件夹中并在模块的__init__.py文件中导包生效的。

所以首先就是先创建一个wizard文件夹,然后在wizard文件夹中也像models文件夹一样新建一个__init__.py文件使其变成一个可导的包,之后别急着去写瞬态模型,为了怕遗忘导包导致的报错阻碍读者的实验,先在模块__init__.py文件中导包

/book_warehouse_management/__init__.py

# -*- coding: utf-8 -*-

from . import models
from . import wizard # 导向导wizard的包

然后在wizard包里新建wizard瞬态模型的py文件

此时同样不着急写代码,先在wizard的__init__.py中导包

/wizard/__init__.py

from . import book_purchase_wizard

之后就可以写向导的瞬态模型了

为了做出上面图中的样式

 则需要写一个向导的主表和它的子表,主表用于展现内容,子表用于存储回写的数据

在/wizard/book_purchase_wizard.py中写下如下代码

from odoo import fields, api, models
from odoo.exceptions import UserError


class book_purchase_wizard(models.TransientModel):
    _name = 'book.purchase.wizard'
    _description = '下推采购向导'

    def get_line_wizard_ids(self):
        record_ids = self.env.context.get('active_ids')
        print(record_ids)
        line_wizard_ids = []
        for line in self.env['book.number.keep.list'].browse(record_ids):
            line_wizard_ids.append((0, 0, {
                'keep_list_ids': line.id,
                'need_push_num': line.book_need_push,
            }))
        return line_wizard_ids

    push_man = fields.Many2one('hr.employee', '下推采购人', default=lambda self: self.env.user.employee_id)
    line_wizard_ids = fields.One2many('book.purchase.line.wizard', 'wizard_id', string='待下推采购清单',
                                      default=get_line_wizard_ids)

    def action_create_action(self):
        print('向导确认按钮生效')


class book_purchase_line_wizard(models.TransientModel):
    _name = 'book.purchase.line.wizard'
    _description = '下推向导明细'

    wizard_id = fields.Many2one('book.purchase.wizard')
    keep_list_ids = fields.Many2one('book.number.keep.list', string='待下推采购书名id')
    name = fields.Char('书籍名称', related='keep_list_ids.name')
    book_image = fields.Binary('书籍封面', related='keep_list_ids.book_image')
    need_push_num = fields.Integer('待下推数量', related='keep_list_ids.book_need_push')
    now_push_num = fields.Integer('本次下推数量')

    @api.constrains('now_push_num', 'need_push_num')
    def check_push_num(self):
        for record in self:
            if record.now_push_num > record.need_push_num:
                raise UserError('本次下推数量不能大于待下推数量')

向导模型使用的与基础表模型的models.Model不一样,向导模式使用的是瞬态模型,即models.TransientModel,注意区分。

在写完wizard模型后,要为模型增加访问权限以保证非superadmin账户也可以查看

进入/security/ir.model.access.csv文件

增加以下内容

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink

access_book_purchase_wizard,book.purchase.wizard,model_book_purchase_wizard,,1,1,1,1
access_book_purchase_line_wizard,book.purchase.line.wizard,model_book_purchase_line_wizard,,1,1,1,1

CSV文件可以通过pycharm的CSV插件更好的查看内容

/wizard/book_purchase_wizard_views.xml中写向导的配套的视图

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

        <record id="book_purchase_wizard_view_form" model="ir.ui.view">
            <field name="name">下推采购单向导form</field>
            <field name="model">book.purchase.wizard</field>
            <field name="arch" type="xml">
                <form string="下推生产">
                    <group>
                        <field name="push_man" readonly="1"/>
                    </group>
                    <notebook>
                        <page string="下推采购清单">
                            <field name="line_wizard_ids">
                                <tree editable="top" create="false">
                                    <field name="name"/>
                                    <field name="book_image" widget="image" class="oe_avatar oe_left"/>
                                    <field name="need_push_num"/>
                                    <field name="now_push_num" sum="总下推采购数量"/>
                                </tree>
                            </field>
                        </page>
                    </notebook>

                    <footer>
                        <button name="action_create_action" string="确认下推采购" type="object" class="btn-primary"/>
                        <button string="取消" class="btn-secondary" special="cancel"/>
                    </footer>
                </form>
            </field>
        </record>

        <record id="xrh_project_wizard_action" model="ir.actions.act_window">
            <field name="name">采购清单</field>
            <field name="res_model">book.purchase.wizard</field>
<!--            <field name="binding_model_id" ref="model_book_number_keep_list"/>-->
            <field name="view_mode">form</field>
            <field name="target">new</field>
        </record>

    </data>
</odoo>

其中的

<field name="binding_model_id" ref="model_book_number_keep_list"/>

按正常的向导写法应该是要写的,该向导按钮将会出现在对应的模型的“活动”按钮中,但由于目前我们已经有了tree视图的button替代了,所以不写或注释这个标签。

如果在练习的过程中写了这个标签并升级了模块,若不希望在对接按钮后注释升级却依旧有活动按钮的残留,只需要换库重装模块即可,若贸然通过技术-活动/窗口活动-采购清单中删除action则会出现报错无法运行程序。

之前上文提到的列表的那个tree视图的button中的name参数里

 按钮就是通过上图所示激活了向导的活动,然后打开了向导主表的form界面,同时会将按钮下选中的记录的active_ids即记录的record_id传到向导瞬态表,用self.env.context.get('active_ids')去获取就可以了,将record打印一下就能得到一个列表

[1, 2]

这个列表中的每个元素其实就是之前选中的记录在记录表中的id,可以直接用

self.env['book.number.keep.list'].browse(record_ids)

来直接获取到之前的基础表的记录集对象

那么如果想实现上面那种点击按钮后向导中就有之前选中的数据,则需要为向导子表回写数据,只需要通过向导主表的一对多关系字段回写数据即可,先整理数据列表

line_wizard_ids = []
for line in self.env['book.number.keep.list'].browse(record_ids):
    line_wizard_ids.append((0, 0, {
        'keep_list_ids': line.id,
        'need_push_num': line.book_need_push,
    }))

之后再将整理好的数据反回去

return line_wizard_ids

但回写方法写好一定要给一对多字段加默认参数调用方法才能激活方法去回写数据

line_wizard_ids = fields.One2many('book.purchase.line.wizard', 'wizard_id', string='待下推采购清单', default=get_line_wizard_ids)

在按钮点下后通过向导的action打开向导主表,读取字段line_wizard_ids时就同时激活回写方法了,但该方法的位置一定是在字段的上面先被系统读取,否则回写方法无法被系统找到进而报错中断程序运行。

最后最容易遗忘的一步就是将上面所有的视图全部在清单文件__manifest__.py中注册

在/book_warehouse_management/__manifest__.py中按以下顺序注册

'data': [
        'data/book_purchase_order_code.xml',        另一个模块的序列号生成视图,详细见另一篇文章了解用法
        'security/ir.model.access.csv',             权限文件
        'wizard/book_purchase_wizard_views.xml',    向导配套视图
        'views/book_number_keep_list_views.xml',    主表视图
        'views/book_need_push_list.xml',            待下推列表视图
        'views/book_purchase_manager_views.xml',
        'views/book_warehouse_management_menu_views.xml',
    ],

这里注意,wizard的xml文件要优先于按钮所在的xml视图的上方先被系统读取,否则在换库、模块重装和模块升级时都会报错:

全局找不到xml的id(book_warehouse_management.xrh_project_wizard_action)

所以在安装/升级模块之前,优先检查一下清单文件的加载顺序,一般这个技术点中的报错会第二个报这里的错。

升级/安装模块,如果没有报错则可进入界面去查看效果,但没有下推效果,仅会在pycharm的终端中看到日志中打印的文字,如果想将向导中的数据下推则

def action_create_action(self):
    print('在这个方法中写下推逻辑')

以上就是tree按钮和向导联动技术点的全部内容,有任何问题不要发私信,私信功能已经关闭,提问请在评论区提问。

猜你喜欢

转载自blog.csdn.net/weixin_45325204/article/details/126971887