跳至内容

Odoo基础扩展

1.视图

    通用格式:

    <record model="ir.ui.view" id="view_id">

        <field name="name">view.name</field>

        <field name="model">object_name</field>

        <field name="priority" eval="16"/>

        <field name="arch" type="xml">

            <!-- view content: <form>, <tree>, <graph>, ... -->

        </field>

    </record>

 

   1.1 Tree视图

   以表格形式展示需要展示的所有数据

 

   1.2 Form视图

   以一个模型(表)展示模型的数据,通常与sheet(页面模板)标签、group(页面块)标签配合使用

 

   1.3 Search视图

   搜索视图,通常结构是先写字段再写filter(过滤器),而过滤器又通常含有domain(域)和context(上下文)配合使用    

 

   1.4 Calendar视图(日历)

   py文件中需要设置开始时间和结束时间及其方法,在xml中calendar标签中需要声明属性date_start、date_stop、color

 

   1.5 Gantt视图(水平条形项目计划、进度)

 

   1.6 Graph视图(图表)

      1)Bar(default;条形图)

      2)Line(折线图)

      3)Pie(饼状图)

 

   1.7 Kanban视图(组织发布任务或分阶段)

 

2.关系

   2.1 关系(字段)类型--模型之间的关系

      (1)One2many

         定义:otm = fields.One2many('关联对象(模型名)', '关联字段', string=''...)

         PS:One2many的关联对象,要在关联对象中Many2one回来,否则会报错,其他两种关系类型单独使用则不用

      (2)Many2one

         定义:mto = fields.Many2one('关联对象', string...)

      (3)Many2many

         定义:mtm = fields.Many2many('关联对象', '关联表/中间表', '关联字段1', '关联字段2', string...)

         PS:其中关联表/中间表和关联字段可不填

 

   2.2 属性关联字段

      定义:related='所在模型的字段.该字段的关联模型的字段.该字段的关联模型的字段...'

      通常与关系类型配合使用

      如:两个模型a_model、b_model,a_model含有test1、rela,b_model中含有test2字段

      rela = fields.Many2one('b_model', string='关联b')

      test1 = fields.Float(related='rela.test2', string='关联test2')

 

3.继承

   3.1 模型

      3.1.1 在原有的模型中继承(不舍模型名,默认)

            1)添加,字段或方法

            2)覆盖,字段或方法

            3)添加,约束或警告

 

      3.1.2 创建新的模型中继承(设置模型名且与父模型名不同)

         提供父记录的透明访问

 

   3.2 视图(基本视图或报表继承)

        例子:

        <record id="idea_category_list2" model="ir.ui.view">

            <field name="name">id.category.list2</field>

            <field name="model">idea.category</field>

            <field name="inherit_id" ref="id_category_list"/>

            <field name="arch" type="xml">

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

                  <field name="idea_ids" string="Number of ideas"/>

                </xpath>

                

                <-- 或者用定位元素的写法 -->【但如果字段在同一视图中多次出现,则应始终使用XPath语法。】

                <field name='description' position="after">

                  <field name="idea_ids" string="Number of ideas"/>

                </xpath>

                <-- end -->

            </field>

        </record>

        PS:expr的内容是需要继承的元素,position是具体操作“(inside:添加属性),(replace:替换元素),(before:匹配元素前插入),(after:匹配元素后插入),                           (attributes:匹配元素更改属性)”

 

    3.3 模板

        3.3.1 视图类型的qweb文件继承

            1)在statc/xml目录下新建一个xml文件

            2)编写以下内容

                #xml

                <template id="唯一的id" xml:space="preserve">

                    <t t-extend="要继承扩展的template的name属性值">

                        <t t-jquery="使用选择器来定位" t-operation="相当于position">

                            //扩展的内容,一般用html语法+qweb语句编写

                        </t>

                    </t>

                </template>

                #manifest

                "qweb": [

                    "static/src/xml/qweb_file.xml",

                ],

        

        3.3.2 data类型的qweb文件继承

            1)在views目录下新建一个xml文件

            2)编写以下内容

                #xml

                <template id="唯一id" inherit_id="模块.继承的templateid">

                    <xpath expr="xpath定位语句">

                        //引入的内容,一般是link标签和script标签,把static/src目录下的css、js子目录的文件引入

                    </xpath>

                </template>

                #manifest

                "data": [

                    "views/XXX.xml",

                ],

 

4.常用api

    1) one: 用于self单一记录的情况

    2) multi: 用于self指多个记录的合集

    3) model: 此时的self仅代表模型本身,不含任何记录

    4) contrains: 字段的代码约束

    5) depends: 主要用于compute方法,depends就是用来标明该方法依赖于哪些字段的

    6) onchange: 当字段发生改变时,触发绑定的函数方法

    7) returns: 主要是用来指定返回值的格式,它接受三个参数,第一个是返回值的model,第二个是向下兼容的method方法,第三个为向上兼容的method方法

 

5.报表

    5.1 设置基本参数

    例:

        <report

            id="report_session"

            model="openacademy.session"

            string="Session Report"

            name="openacademy.report_session_view" //模块名.模板id(必填)

            file="openacademy.report_session"  //模块名.模板id(用于更好地关联模板)

            report_type="qweb-pdf" />

    

    5.2 template模板(QWeb规则)

    例:

        <template id="report_session_view">

            <t t-call="web.html_container">

                <t t-foreach="docs" t-as="doc">

                    <t t-call="web.external_layout">

                        <div class="page">

                            <h2 t-field="doc.name"/>

                            <p>From <span t-field="doc.start_date"/> to <span t-field="doc.end_date"/></p>

                            <h3>Attendees:</h3>

                            <ul>

                                <t t-foreach="doc.attendee_ids" t-as="attendee">

                                    <li><span t-field="attendee.name"/></li>

                                </t>

                            </ul>

                        </div>

                    </t>

                </t>

            </t>

        </template>

    

    5.3 QWeb常用指令

        1) t-esc:输出数据

        2) t-if、t-elif、t-else:条件判断

        3) t-foreach:循环处理,通常与t-as使用,t-as用于表示foreach操作的模型的自定义名称

        4) t-att-$name:设置属性($name为属性名如a、class、name)

                        需要写多个属性时 t-att=mapping

                        例如:<div t-att="{'a': 1, 'b': 2}"/>

                            #输出

                            <div a="1" b="2"></div>

                        也可以写成 t-att=pair

                        例如:<div t-att="['a', 'b']"/>

                            #输出

                            <div a="b"></div>

        5) t-set:定义一个变量名,通常与t-value连用(也可不用,则需加入别的标签或值),t-value是用表达式来表示t-set的内容或值

        6) t-call:用于调用其他模板

        7) t-field:用于获取记录字段,但要注意不同模型的使用

        8) t-options:用于自定义字段,最常用的是widget组件使用

                      例如:t-field-options='{"widget": "image"}'

 

6.权限

    权限管理四个层次:

        1.菜单级别:对用户是否隐藏菜单

        2.对象级别:对表是否有“创建,读取,修改,删除”

        3.记录级别:对自己或下级的访问权限,例如业务员对自己所创客户有访问权限,经理可以访问对管辖的业务员所有的客户对象

        4.字段级别:一个对象或表上的某些字段的访问权限

    

    1) 权限组建立

        例:

        <record id="base.group_hr_manager" model="res.groups">

            <field name="name">Manager</field>

            <field name="comment">the user will have an access to the human resources configuration as well as statistic reports.</field>

            <field name="category_id" ref="base.module_category_human_resources"/>

            <field name="implied_ids" eval="[(4, ref('base.group_hr_user'))]"/>

            <field name="users" eval="[(4, ref('base.user_root'))]"/>   //把admin用户加入该组中

         </record>

        @name: 用户组名,这个可以翻译的

        @comment: 用户组的注释

        @category_id: 用户组所属的模块名

        @implied_ids(记录级别,上下级控制): 基于哪个用户组,这个层级关系 <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>是最基础的

        用户名,最初是基于这个,后面一层一层递增,像上面 base.group_hr_user 定义时就是基于最基础

        @users:预设用户属于这个用户组

 

 

    2) 组控制菜单显示(菜单级别)

        <record model="ir.ui.menu" id=" memu_id1">

            <field name="name" >menu1</field>

            <field name="groups_id" eval="[(6,0,[ref('A'),ref('B')]),]"/>           

            <field name="sequence">1</field>

        </record>

        @ name 菜单名称

        @ groups_id 哪些组可以访问该菜单

        @ sequence 该菜单的序号

        这样A组与B组的成员都可以访问menu1菜单,menu1菜单的显示顺序为1

        注:eval 后面解释,多个组访问用“,”隔开    

        

        <menuitem id="menu_id2 " name="menu2" parent="menu_id1" sequence="1" groups="A,B "/>

        @ name 菜单名称

        @ parent 父类菜单 如果没有可以不写parent

        @ groups哪些组可以访问该菜单

        这样menu1的子菜单menu2可以被A组合B组的成员访问

 

    3) 规则建立(对象级别)

        例:

        <record model="ir.rule" id="rule1">

            <field name="name">rule1</field>

            <field name="model_id" ref="model_model1"/>

            <field name="global" eval="True"/>

            <field name="domain_force">[1,’=’,1]</field>

            <field name="groups" eval="[(4,ref('A'))]"/>

        </record>

        @ name 规则名称

        @ model_id 依赖的模块

        @ global 是否是全局

        @ domain_force 过滤条件

        @ groups 属于哪个组

        这样A组的成员就可以取到model_model1的所有数据

 

        eval:

            many2many

            (0,0,{values}) 根据values里面的信息新建一个记录。

            (1,ID,{values})更新id=ID的记录(写入values里面的数据)

            (2,ID) 删除id=ID的数据(调用unlink方法,删除数据以及整个主从数据链接关系)

            (3,ID) 切断主从数据的链接关系但是不删除这个数据

            (4,ID) 为id=ID的数据添加主从链接关系。

            (5) 删除所有的从数据的链接关系就是向所有的从数据调用(3,ID)

            (6,0,[IDs]) 用IDs里面的记录替换原来的记录(就是先执行(5)再执行循环IDs执行(4,ID))

            例子[(6, 0, [8, 5, 6, 4])] 设置 many2many to ids [8, 5, 6, 4]

 

            one2many

            (0, 0,{ values })根据values里面的信息新建一个记录。

            (1,ID,{values}) 更新id=ID的记录(对id=ID的执行write 写入values里面的数据)

            (2,ID) 删除id=ID的数据(调用unlink方法,删除数据以及整个主从数据链接关系)

            例子:

            [(0,0,{'field_name':field_value_record1,...}),(0,0,{'field_name':field_value_record})]

            many2one的字段比较简单,直接填入已经存在的数据的id或者填入False删除原来的记录。

 

    4)设置ir.model.access.csv (也相当于对象级别,设置某个组对某个模型的增删改查权限)

        @id 随便取

        @name 随便取

        @model_id:id 这个就是你所定义的对象了

        @group_id:哪个组

        @perm_read","perm_write","perm_create","perm_unlink" 增删改查权限了。1代表有权限

    

    5)字段级别

    <field name="company_id" groups="base.group_multi_company" widget="selection"/>

    

    隐藏技巧:

        1)直接隐藏(所有人)

        <group name="owner" position="attributes">

            <attribute name="invisible">True</attribute>

        </group>

        2)满足某些条件隐藏

        <xpath expr="//field[@name='parent_id']" position='attributes'>

            <attribute name="attrs">{'invisible': [('passenger','=', True)]}</attribute>

        </xpath>

        3)通过组来隐藏

        <xpath expr="//field[@name='type']" position="attributes">

            <attribute name="groups">base.group_no_one</attribute>

        </xpath>

        4)菜单的隐藏

        <record model="ir.ui.menu" id="crm.menu_crm_opportunities">

            <field eval="[(6,0, [ref('base.group_no_one'),])]" name="groups_id"/>

        </record>

        5)字段显示权限,其他组则隐藏

        <field name="company_id" groups="base.group_multi_company" widget="selection"/>

        6)在model中判断

        self.pool.get('res.users').has_group(cr, uid, 'sale.group_discount_per_so_line')

 

7.国际化

    每个模块都可以在i18n目录中提供自己的翻译,方法是将文件命名为LANG.po,其中LANG是语言的语言环境代码,或者语言和国家/地区组合不同(例如pt.po或pt_BR.po)。Odoo将为所有启用的语言自动加载翻译。

    更改翻译流程:创建目录 模块名/i18n/ -> 设置‣翻译‣导入/导出‣导出翻译(指定模块,导出翻译) -> 将导出文件放入创建目录 -> 更改翻译

    msgid:为字段显示名称

    mgstr:为翻译显示名称

 

8.向导

    向导与其他的模型不同,其基类不是常见的Model而是TransientModel。

    向导记录不是永久性的,会在一段时间后自动从数据库中删除,所以被称为瞬态

    向导不需要访问权限,即用户拥有向导记录的所有权限

    向导记录可以通过many2one字段引用普通记录或向导记录,但反之则不不行

 

9.网页服务(RPC)

    XML-RPC

 

    JSON-RPC

 

    Odoo-RPC

 

10.消息机制

    在模型中整合消息系统是很简单的,只需要从mail.thread继承模型并将对应的字段和widget添加到视图中就可以了。

    例如:

        #model

        _inherit = ['mail.thread']

        #view

        <field name="message_ids" widget="mail_thread"/>

 

    1.发布消息

     * message_post(self, body='', subject=None, message_type='notification', subtype=None, parent_id=False, attachments=None, content_subtype='html', **kwargs)

            在一个会话列表中发布一条新消息,返回新的mail.message ID

     * message_post_with_view(views_or_xmlid, **kwargs)

            发送一条使用指定id对应视图进行渲染的消息。这个方法只能单独使用。

     * message_post_with_template(template_id, **kwargs)

            使用模板来发送消息

 

    2.接收消息

    * message_new(msg_dict, custom_values=None)

        当收到的消息不属于一个已存在的讨论列表时由message_process调用,默认是基于相关的模型创建一个新讨论记录,其邮件内容直接被提取用于创建新记录,可以通过覆盖该方法来添加新特性。

    * message_update(msg_dict, update_vals=None)

        当一个收到已存在的讨论列表的消息时由message_process调用,默认用邮件里的update_vals来更新记录。可通过覆盖方法来添加其他特性。

 

    3.关注者管理

    * message_subscribe(partner_ids=None, channel_ids=None, subtype_ids=None, force=True)

        添加参与者

    * message_subscribe_users(user_ids=None, subtype_ids=None)

        将message_subscribe封装,只是用用户替代partner

    * message_unsubscribe(partner_ids=None, channel_ids=None)

        将合作伙伴从记录的订阅列表移除

    * message_unsubscribe_users(user_ids=None)

        封装message_unsubscribe,用user替代partner

 

    - 记录变化 --

    为了对字段进行监听,只需要将track_visibility 属性设置为onchange(当字段值改变时展示在通知中),

    always(该值总是会被显示在通知中,一般用于让通知内容更好理解)

 

odoo更新模型报错解决方案