一篇文章带你入门odoo

不念不忘少年蓝@ 2023-08-17 17:10 348阅读 0赞
  1. 激活开发者模式

    • 点击设置(点下左上角的四个小方块, 就能看到)
    • 点击页面右侧的激活开发者模式
  2. 成为超级用户

    • 点击右上方开发者工具(小虫子按钮)
    • 点击成为超级用户
  3. 创建应用

    • python odoo-bin scaffold example addons

      • python odoo-bin scaffold 模型名称 放置它的位置
      • 执行后会发现在odoo-12.0/addons里面有个新建的文件夹example, 里面会包含__init__.py __manifest__.py controllers demo models security views这几个文件夹
      • 应用目录

        • controllers

          • 控制器 (HTTP路径)
        • data

          • 演示和数据XML
        • doc

          • 模型说明
        • models

          • 定义模型
        • report

          • 报告
        • security

          • 权限管理
        • i18n

          • 翻译
        • views

          • 视图和模型
        • static

          • CSS
          • JS
          • IMG
          • LIB
        • tests

          • 存放 python 和 yml 测试用例
        • wizard

          • 放临时的 model 和视图

        __manifest__.py

  1. # -*- coding: utf-8 -*- { # 模型名 'name': "example", # 摘要 'summary': """ Short (1 phrase/line) summary of the module's purpose, used as subtitle on modules listing or apps.openerp.com""", # 介绍 'description': """ Long description of module's purpose """, # 作者 'author': "My Company", # 网址 # 'website': "http://www.yourcompany.com", # Categories can be used to filter modules in modules listing # Check https://github.com/odoo/odoo/blob/12.0/odoo/addons/base/data/ir_module_category_data.xml # for the full list # 类别 'category': 'Uncategorized', # 版本号 'version': '0.1', # any module necessary for this one to work correctly # 依赖 'depends': ['base'], # always loaded # 数据文件 'data': [ # 'security/ir.model.access.csv', 'views/views.xml', 'views/templates.xml', ], # only loaded in demonstration mode # 演示文件 'demo': [ 'demo/demo.xml', ], }
  1. 安装应用

    1. 重启odoo服务
    2. 点击刷新本地模型列表
    3. 弹出窗口点击更新按钮
    4. 删除搜索框内容,然后输入example
    5. 点击安装

      • 以后执行步骤4时, 点击三个小点点. 然后点击升级按钮
  2. 新建模型
    修改addons/example/models/models.py
  1. # -*- coding: utf-8 -*- import datetime from odoo import models, fields, api class example(models.Model): _name = 'example.example' name = fields.Char() active = fields.Boolean(default=True, string='归档', required=True) # 系统保留变量, False时不在主页显示,需要筛选改为True才能显示 price = fields.Float() note = fields.Text() content = fields.Html(readonly=True) my_datetime = fields.Datetime(default=fields.Datetime.now) # my_date = fields.Date(default=fields.Date.today) my_date = fields.Date(default=lambda self: datetime.date.today() + datetime.timedelta(days=4)) select = fields.Selection([ ('1', 'em'), ('2', 'emm'), ('3', 'emmm'), ]) em1_mo = fields.Many2one(comodel_name='example.example1') em1_om = fields.One2many(comodel_name='example.example1', inverse_name='em_mo') em1_mm = fields.Many2many(comodel_name='example.example1', column1='name', column2='fuck_id') my_reference = fields.Reference(selection='_select_objects') @api.model def _select_objects(self): records = self.env['ir.model'].search([]) return [(record.model, record.name) for record in records] + [('', '')] class em1(models.Model): _name = 'example.example1' fuck_id = fields.Integer() em_mo = fields.Many2one('example.example')
  2. 知识内容
  3. * 模型的字段
  4. * 系统字段
  5. * `_name`
  6. * 必需的
  7. * 定义了Odoo系统中模型的名称
  8. * `_description`
  9. * 为模型添加更为友好的描述,更新后在Settings下可发现相应的变化(需开启调试模式Database Structure>Models)
  10. * `_order`
  11. * 默认情况下Odoo使用内置的id进行排序,可以通过逗号分隔指定多个字段进行排序,desc表示降序,仅能使用数据库中存储的字段排序,外部计算后的字段不适用,\_order有些类似SQL语句中的ORDER BY,但无法使用NULL FIRST之类的语句
  12. * 字段共同属性
  13. * string(unicode, 默认:字段名称)
  14. * UI中字段的标签(用户可见)
  15. * required(bool默认:False)
  16. * 如果True该字段不能为空, 则它必须具有默认值或在创建记录时始终给定值
  17. * help(unicode默认:'')
  18. * 长格式, UI中为用户提供帮助工具提示
  19. * index(bool默认:False)
  20. * 请求Odoo 在列上创建数据库索引
  21. * readonly(bool默认:False)
  22. * 是否只读
  23. * Model字段类型
  24. * 字段共同属性
  25. * string(unicode, 默认:字段名称)
  26. * UI中字段的标签(用户可见)
  27. * required(bool默认:False)
  28. * 如果True该字段不能为空, 则它必须具有默认值或在创建记录时始终给定值
  29. * help(unicode默认:'')
  30. * 长格式, UI中为用户提供帮助工具提示
  31. * index(bool默认:False)
  32. * 请求Odoo 在列上创建数据库索引
  33. * readonly(bool默认:False)
  34. * 是否只读
  35. * 常用字段属性
  36. * default
  37. * 默认值
  38. * Binary
  39. * Binary字段用于存储二进制文件,如图片或文档
  40. * `a = fields.Binary()`
  41. * Float
  42. * Float用于存储数值,其精度可以通过数字长度和小数长度一对值来进行指定
  43. a = fields.Float( string='float', digits=(14, 4), # Optional precision (total, decimals) )
  44. * Boolean
  45. * Boolean字段用于存储True/False布尔值
  46. * `a = fields.Boolean()`
  47. * Integer
  48. * Integer即为整型
  49. * `a = fields.Integer()`
  50. * Char
  51. * Char用于字符串
  52. * `a = fields.Char(string='aa', required=True)`
  53. * Date
  54. * Date字段用于存储日期,ORM中以字符串格式对其进行处理,但以日期形式存放在数据库中,该格式在odoo.fileds.DATE\_FORMAT中定义
  55. * `my_date = fields.Date(default=fields.Date.today)`
  56. * `my_date = fields.Date(default=lambda self: datetime.date.today() + datetime.timedelta(days=4))`
  57. * Datetime
  58. * Datetime用于存储日期时间,在数据库中以UTC无时区时间(naive)存放,ORM中以字符串和UTC时间表示,该格式在odoo.fields.DATETIME\_FORMAT中定义
  59. * `my_datetime = fields.Datetime(default=fields.Datetime.now)`
  60. * Text
  61. * Text用于多行字符串
  62. * `notes = fields.Text()`
  63. * Monetary
  64. * 货币
  65. * `a=fields.Monetary()`
  66. * Html
  67. * Used to store HTML, provides an HTML widget.
  68. * Html类似text字段,但一般用于存储富文本格式的HTML
  69. * strip\_style=True:清除所有样式元素
  70. * strip\_class=True:清除类属性
  71. * `description = fields.Html()`
  72. * Selection
  73. * Store Text in database but propose a selection widget. It induces no selection constraint in database. Selection must be set as a list of tuples or a callable that returns a list of tuples
  74. * Selection用于选择列表,由值和描述对组成,选择的值将存储在数据库中,可以为字符串或整型,描述默认可翻译,虽然整型的值看似简洁,但注意Odoo会把0解析为未设置(unset),因而当存储值为0时不会显示描述
  75. * index: Tells Odoo to index for faster searches replaces the select kwarg
  76. select = fields.Selection([ ('1', 'em'), ('2', 'emm'), ('3', 'emmm'), ], required=True, default='1')
  77. * Many2one
  78. * Store a relation against a co-model
  79. * comodel\_name指定绑定多对一的模型名, 即类名
  80. * `em1_mo = fields.Many2one(comodel_name='example.example1')`
  81. * Many2many
  82. * Store a relation against many2many rows of co-model
  83. * Many2many会新建一个中间表, relation指定中间表的表名
  84. * 例:
  85. `python _name = 'emm.a' e = Many2many( comodel_name='emmm.b', # 关联的表 relation='emmm_a_b_rel', # 可选, 中间表名 column1='a_id', # 当前表的字段名 column2='b_id', # 关联的其他表的字段名 string='Tags')`
  86. * One2many
  87. * Store a relation against many rows of co-model
  88. * 新建one2many前需要先写many2one, 并且数据库的外键会建立在many2one
  89. * comodel\_name: 指定绑定一对多的模型名, 即类名
  90. * inverse\_name: 指定绑定一对多的模型的Many2one字段的名
  91. * domain
  92. * 过滤, 例:`domain=[('id','=',1)]`
  93. class em(models.Model): _name = 'example.example' em1_om = fields.One2many(comodel_name='example.example1', inverse_name='em_mo') class em1(models.Model): _name = 'example.example1' em_mo = fields.Many2one('example.example')
  94. * Reference
  95. * Store an arbitrary reference to a model and a row
  96. * 事先不能决定关联的目标模型时, 这种情况需要使用reference将目标模型的选择权留给用户
  97. my_reference = fields.Reference(selection='_select_objects') @api.model def _select_objects(self): records = self.env['ir.model'].search([]) return [(record.model, record.name) for record in records] + [('', '')]
  98. * 保留字段
  99. * Odoo在所有模型中都创建了以下几个字段,这些字段由系统管理,是系统保留的字段, 用户不应定义
  100. * id(Id)
  101. * 模型中记录的唯一标识符
  102. * create\_date(Datetime)
  103. * 记录的创建日期
  104. * create\_uid(Many2one)
  105. * 创建记录的用户
  106. * write\_date(Datetime)
  107. * 记录的最后修改日期
  108. * write\_uid(Many2one)
  109. * 上次修改记录的用户
  110. * Method and decorator
  111. * @api.returns
  112. * This decorator guaranties unity of returned value. It will return a RecordSet of specified model based on original returned value:
  113. @api.returns('res.partner') def afun(self): ... return x # a RecordSet
  114. * @api.one
  115. * This decorator loops automatically on Records of RecordSet for you. Self is redefined as current record:
  116. @api.one def afun(self): self.name = 'toto'
  117. * @api.multi
  118. * Self will be the current RecordSet without iteration. It is the default behavior:
  119. @api.multi def afun(self): len(self)
  120. * @api.model
  121. * This decorator will convert old API calls to decorated function to new API signature. It allows to be polite when migrating code.
  122. @api.model def afun(self): pass
  123. * @api.constrains
  124. * This decorator will ensure that decorated function will be called on create, write, unlink operation. If a constraint is met the function should raise a openerp.exceptions.Warning with appropriate message.
  125. * @api.depends
  126. * This decorator will trigger the call to the decorated function if any of the fields specified in the decorator is altered by ORM or changed in the form
  127. @api.depends('name', 'an_other_field') def afun(self): pass
  128. * @api.onchange
  129. * This decorator will trigger the call to the decorated function if any of the fields specified in the decorator is changed in the form
  130. @api.onchange('fieldx') def do_stuff(self): if self.fieldx == x: self.fieldy = 'toto'
  131. * @api.noguess
  132. * This decorator prevent new API decorators to alter the output of a method
  1. 升级应用

    1. 重启odoo服务
    2. 在搜索框输入example
    3. 点击升级
  2. 修改数据文件
    修改addons/example/views/views.xml文件
  1. <odoo>
  2. <data>
  3. <!-- explicit list view definition -->
  4. <!--选择显示哪些字段, 默认是name,即ui-->
  5. <record model="ir.ui.view" id="example.list">
  6. <field name="name">example模型表头</field>
  7. <field name="model">example.example</field>
  8. <field name="arch" type="xml">
  9. <tree>
  10. <field name="name"/>
  11. <field name="active"/>
  12. <field name="price"/>
  13. </tree>
  14. </field>
  15. </record>
  16. <!-- actions opening views on models -->
  17. <!--选择哪些功能动作即action-->
  18. <!--res_model是目标模块的标识符 -->
  19. <record model="ir.actions.act_window" id="example.action_window">
  20. <field name="name">example act_window</field>
  21. <field name="res_model">example.example</field>
  22. <!--
  23. tree, 显示数据
  24. form, 新建数据
  25. 默认为tree
  26. -->
  27. <field name="view_mode">tree,form</field>
  28. </record>
  29. <!-- server action to the one above -->
  30. <!--执行py代码-->
  31. <record model="ir.actions.server" id="example.action_server">
  32. <field name="name">example server</field>
  33. <field name="model_id" ref="model_example_example"/>
  34. <field name="state">code</field>
  35. <!--
  36. <field name="code">里面包裹的是py代码
  37. action将作为下一个要执行的操作返回给客户端
  38. -->
  39. <field name="code">
  40. action = {
  41. "type": "ir.actions.act_window",
  42. "view_mode": "tree,form",
  43. "res_model": "example.example",
  44. }
  45. </field>
  46. </record>
  47. <!-- Top menu item -->
  48. <!--顶部菜单-->
  49. <menuitem name="example" id="example.menu_root"/>
  50. <!-- menu categories -->
  51. <!--分菜单-->
  52. <menuitem name="Menu 1" id="example.menu_1" parent="example.menu_root"/>
  53. <menuitem name="Menu 2" id="example.menu_2" parent="example.menu_root"/>
  54. <!-- actions -->
  55. <!--菜单绑定动作-->
  56. <menuitem name="List" id="example.menu_1_list" parent="example.menu_1"
  57. action="example.action_window"/>
  58. <menuitem name="Server to list" id="example" parent="example.menu_2"
  59. action="example.action_server"/>
  60. </data>
  61. </odoo>
  62. 重复步骤4 升级应用
  63. 知识内容
  64. * 数据文件仅在安装或更新模块时才加载数据文件的内容
  65. * 模块的数据通过带有`<record>`元素的数据文件, XML文件声明.每个`<record>`元素都创建或更新数据库记录
  66. * 数据文件必须在要manifest文件中声明数据文件, 它们可以在`data`列表(始终加载)或`demo`列表中声明(仅在演示模式下加载).
  67. * 属性
  68. * model
  69. * 记录的Odoo模块的名称
  70. * id
  71. * 一个外部标识符, 用于被引用
  72. * `<field>`
  73. * name标识字段名称
  74. * `<field>`的innnerText是`<field>`的值
  75. * menuitem
  76. * 必须先声明相应的Action, 因为数据文件按顺序执行, 在id创建菜单之前, Action必须存在于数据库中
  77. * 在创建完菜单后必须成为超级用户才能正常显示新建的菜单
  78. * menuitem 只有绑定action, 或子menuitem绑定了action才能显示出来
  79. * 属性
  80. * id: 定义唯一标记
  81. * action: 绑定动作
  82. * parent: 父菜单
  83. * sequence: 优先级, 数字越小优先级越高, 显示越靠前,最小为0
  84. * groups: 绑定权限
  85. * name: 菜单名称
  86. * view
  87. * **视图定义了模块记录的显示方式(Views define the way the records of a model are displayed)**.每种类型的视图代表一种可视化模式(记录列表, 其聚合图, ......).可以通过类型(例如合作伙伴列表)或特别是通过其ID 来一般性地请求视图.对于通用请求, 将使用具有正确类型和最低优先级的视图(因此每种类型的最低优先级视图是该类型的默认视图).
  88. * 对于view 中的`<record>`的id, 会被存到数据库中, 而且当你修改`<record>`的model, 然后再次执行, 则`<record>`的model仍为修改前的model, 不报错, 且正常使用
  89. * 解决方法:
  90. * 修改`<record>`的id
  91. * 或将`<record>`删除, 重启服务,升级模块, 然后再写`<record>`
  1. 自定义添加数据的表单
    修改addons/example/models/models.py
  1. # -*- coding: utf-8 -*- import datetime from odoo import models, fields, api class example(models.Model): _name = 'example.example' name = fields.Char() active = fields.Boolean(default=True, string='归档',required=True) # 系统保留变量, False时不在主页显示,需要筛选改为True才能显示 price = fields.Float() note = fields.Text() content = fields.Html(readonly=True) my_datetime = fields.Datetime(default=fields.Datetime.now) # my_date = fields.Date(default=fields.Date.today) my_date = fields.Date(default=lambda self: datetime.date.today() + datetime.timedelta(days=4)) select = fields.Selection([ ('1', 'em'), ('2', 'emm'), ('3', 'emmm'), ]) em1_mo = fields.Many2one(comodel_name='example.example1') em1_om = fields.One2many(comodel_name='example.example1', inverse_name='em_mo') em1_mm = fields.Many2many(comodel_name='example.example1', column1='name', column2='fuck_id') my_reference = fields.Reference(selection='_select_objects') @api.model def _select_objects(self): records = self.env['ir.model'].search([]) return [(record.model, record.name) for record in records] + [('', '')] # 添加状态值和, 按钮事件 state = fields.Selection( [('1', '状态1'), ('2', '状态2'), ('3', '状态3')], readonly=True, default='1' ) """ [(状态值, 状态条中显示的内容), ('1', '状态1'),...] """ def button1(self): return self.write({'state': '1'}) def button2(self): return self.write({'state': '2'}) def button3(self): return self.write({'state': '3'}) class em1(models.Model): _name = 'example.example1' fuck_id = fields.Integer() em_mo = fields.Many2one('example.example')
  2. 修改addons/example/views/views.xml文件
  3. <odoo>
  4. <data>
  5. <record model="ir.ui.view" id="example.list">
  6. <field name="name">列表显示字段</field>
  7. <field name="model">example.example</field>
  8. <field name="arch" type="xml">
  9. <tree>
  10. <field name="name"/>
  11. <field name="active"/>
  12. <field name="price"/>
  13. <field name="note"/>
  14. <field name="content"/>
  15. <field name="my_date"/>
  16. <field name="my_datetime"/>
  17. <field name="select"/>
  18. <field name="em1_mo"/>
  19. <field name="em1_om"/>
  20. <field name="em1_mm"/>
  21. <field name="my_reference"/>
  22. </tree>
  23. </field>
  24. </record>
  25. <!--动作-->
  26. <record id="example.root_menu_action_view" model="ir.actions.act_window">
  27. <field name="type">ir.actions.act_window</field>
  28. <field name="name">我会被显示出来</field>
  29. <field name="res_model">example.example</field>
  30. </record>
  31. <!--自定义form表单-->
  32. <record id="example.example_form_view" model="ir.ui.view">
  33. <field name="model">example.example</field>
  34. <field name="arch" type="xml">
  35. <form>
  36. <header>
  37. <!--三个按钮, 一个状态条-->
  38. <!--
  39. - button
  40. - name: 点击时执行的函数名
  41. - string: 按钮显示内容
  42. - states: 当状态值为多少时, 该按钮可见, 不设置则永远可见
  43. - <field name="state" widget="statusbar"/>
  44. - statusbar_visible: 根据state值确定哪些状态在状态条上显示
  45. -->
  46. <button states="1" name="button2" string="当前状态值为1, 点击设置为2" class="oe_highlight" type="object"/>
  47. <button states="1" name="button3" string="当前状态值为1, 点击设置为3" class="oe_highlight" type="object"/>
  48. <button states="2" name="button3" string="当前状态值为2, 点击设置为3" class="oe_highlight" type="object"/>
  49. <button states="3" name="button1" string="当前状态值为3, 点击设置为1" class="oe_highlight" type="object"/>
  50. <field name="state" widget="statusbar" statusbar_visible="1,2,3"/>
  51. </header>
  52. <sheet>
  53. <group string="group1">
  54. <field name="name"/>
  55. <field name="active"/>
  56. <field name="price" readonly="1"/>
  57. </group>
  58. <group string="group2">
  59. <field name="my_datetime" attrs="{'invisible': [('active', '=', False)]}"/>
  60. <!--
  61. 此处的required的优先级大于models中的required, 但是提交时会弹错
  62. -->
  63. <field name="my_date" required="1"/>
  64. <field name="select" required="0"/>
  65. </group>
  66. <group string="group3">
  67. <field name="em1_mo"/>
  68. <field name="em1_om"/>
  69. <field name="em1_mm"/>
  70. <field name="my_reference"/>
  71. </group>
  72. <notebook string="notebook1">
  73. <page string="page1">
  74. <field name="note"/>
  75. </page>
  76. <page string="page1">
  77. <field name="content"/>
  78. </page>
  79. </notebook>
  80. </sheet>
  81. </form>
  82. </field>
  83. </record>
  84. <menuitem id="example.root_menu" name="example" action="example.root_menu_action_view" sequence="1"/>
  85. </data>
  86. </odoo>
  87. 重复步骤4: 升级应用
  88. 知识内容
  89. * **`model="ir.ui.view"`recoder 不需要绑定任何只要在xml文件中出现既能正常显示**
  90. * 视图被声明为ir.ui.viewModelrecord.视图类型由arch字段的根元素声明
  91. * 表单视图
  92. * 属性
  93. * create="0": 不可新建
  94. * edit="0": 编辑
  95. * delete="0": 删除
  96. * field属性
  97. * widget
  98. * statusbar
  99. * 头部状态条标签
  100. * email
  101. * 电子邮件地址标签
  102. * selection
  103. * 下拉选择标签
  104. * mail\_followers
  105. * 关注者标签
  106. * mail\_thread
  107. * 消息标签
  108. * progressbar
  109. * 进度条,按百分比标签
  110. * one2many\_list
  111. * 一对多列表标签
  112. * many2many\_tags
  113. * 多对多显示标签
  114. * url
  115. * 网站链接标签
  116. * image
  117. * 图片标签
  118. * many2many\_kanban
  119. * 看版标签
  120. * handler
  121. * 触发标签
  122. * radio
  123. * 单选标签
  124. * char\_domain
  125. * 字符域标签
  126. * monetary
  127. * 价格(和精度位数相关)标签
  128. * float\_time
  129. * 单精度时间标签
  130. * html
  131. * html相关标签
  132. * pad
  133. * pad显示相关标签
  134. * date
  135. * 日期标签
  136. * monetary
  137. * 金额标签
  138. * text
  139. * 文本标签
  140. * sparkline\_bar
  141. * 燃尽标签
  142. * checkbox
  143. * 复选框标签
  144. * reference
  145. * 关联标签
  146. * `required`
  147. * 必填
  148. * `readonly`
  149. * 只读
  150. * `invisible`
  151. * 不可见
  152. * 根据条件变化
  153. * `name='123'``invisible="1"`
  154. * `active=True``required="1"`
  155. * 当前字段不是'many2many', 'many2one'状态时`readonly="1"`
  156. attrs="{
  157. 'invisible':[('name','=','123')],
  158. 'required':[('active','=', True)],
  159. 'readonly':[('ttype','not in', ['many2many', 'many2one'])]
  160. }"
  161. * 过滤one2many, many2many, 后面的many
  162. * domain
  163. * `domain="[('id','=',1)]"`
  164. 表单视图还可以使用纯HTML来实现更灵活的布局
  165. <form string="Idea Form">
  166. <header>
  167. <button string="Confirm" type="object" name="action_confirm" states="draft"
  168. class="oe_highlight" />
  169. <button string="Mark as done" type="object" name="action_done"
  170. states="confirmed" class="oe_highlight"/>
  171. <button string="Reset to draft" type="object" name="action_draft"
  172. states="confirmed,done" />
  173. <field name="state" widget="statusbar"/>
  174. </header>
  175. <sheet>
  176. <div class="oe_title">
  177. <label for="name" class="oe_edit_only" string="Idea Name" />
  178. <h1><field name="name" /></h1>
  179. </div>
  180. <separator string="General" colspan="2" />
  181. <group colspan="2" col="2">
  182. <field name="description" placeholder="Idea description..." />
  183. </group>
  184. </sheet>
  185. </form>
  186. * 树视图
  187. > 树视图(也称为列表视图)以表格形式显示记录.他的根元素是`<tree>`.最简单的树形视图, 即只需列出要在表中显示的所有字段(每个字段作为列)
  188. * 属性
  189. * create="0": 不可新建
  190. * edit="0": 编辑
  191. * delete="0": 删除
  192. <tree string="Idea list">
  193. <field name="name"/>
  194. <field name="inventor_id"/>
  195. </tree>
  196. * 搜索视图
  197. > 搜索视图通过列表视图(以及其他聚合视图)自定义关联的搜索字段.他的根元素是`<search>`, 他包含的字段, 定义了哪些时用于搜索的字段
  198. <search>
  199. <field name="name"/>
  200. <field name="inventor_id"/>
  201. </search>
  202. </field>
  203. </record>
  204. <record model="ir.ui.view" id="course_search_view">
  205. <field name="name">course.search</field>
  206. <field name="model">openacademy.course</field>
  207. <field name="arch" type="xml">
  208. <search>
  209. <field name="name"/>
  210. <field name="description"/>
  211. </search>
  212. </field>
  213. </record>
  214. * 如果模块不存在搜索视图, Odoo会生成仅允许在该name字段上搜索的视图.
  1. 权限管理
    添加文件addons/em/security/security.xml
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <odoo>
  3. <record id="example.example_category" model="ir.module.category">
  4. <field name="name">example.example_category</field>
  5. <field name="sequence" eval="1"/>
  6. </record>
  7. <record id="example.example_groups_a" model="res.groups">
  8. <field name="name">example.example_groups_a</field>
  9. <field name="category_id" ref="example.example_category"/>
  10. <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
  11. </record>
  12. <record id="example.example_groups_b" model="res.groups">
  13. <field name="name">example.example_groups_b</field>
  14. <field name="category_id" ref="example.example_category"/>
  15. <!--example.example_groups_a和example.example_groups_b, 只能选一个-->
  16. <field name="implied_ids" eval="[(4, ref('example.example_groups_a'))]"/>
  17. <!--example.example_groups_a和example.example_groups_b, 可以同时选-->
  18. <!--<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>-->
  19. </record>
  20. </odoo>
  21. 修改addons/example/\_\_manifest\_\_.py
  22. ... # always loaded # 数据文件 'data': [ 'security/security.xml', 'views/views.xml', 'views/templates.xml', ], ...
  23. * 两种方法设置字段指定用户组可见
  24. 法一. 修改addons/example/models/models.py
  25. ... # 设置example.example_groups_b组的用户可见 select = fields.Selection([ ('1', 'em'), ('2', 'emm'), ('3', 'emmm'), ], groups="example.example_groups_b") ...
  26. 法二. 修改addons/example/views/views.xml
  27. `xml ... <field name="select" required="0" groups="example.example_groups_b"/> ...`
  28. 个人推荐法一
  29. <record model="ir.actions.act_window" id="example.action_window">
  30. <field name="name">example act_window</field>
  31. <field name="res_model">example.example</field>
  32. <field name="view_mode">tree,form</field>
  33. <!-- 在model中设置groups后, 会自动权限管理 -->
  34. </record>
  35. * 重复步骤4: 升级应用
  36. * 验证权限
  37. 1. 修改群组访问权限
  38. 1. 设置
  39. 2. 用户&公司
  40. 3. 群组
  41. 4. 点击 `example.example_category / example.example_groups_a`
  42. 1. 编辑
  43. 2. 访问权限
  44. 3. 添加明细行
  45. * 名称随意
  46. * 对象, 点击搜索更多后搜索并选择`example.example`
  47. * 读, 写, 创建, 删除权限都勾上
  48. 4. 添加明细行
  49. * 名称随意
  50. * 对象, 点击搜索更多后搜索并选择`example.example1`
  51. * 读, 写, 创建, 删除权限都勾上
  52. 5. 保存
  53. 2. 新建用户
  54. 1. 设置
  55. 2. 用户&公司
  56. 3. 用户
  57. 4. 创建
  58. 5. example.example\_category 选择 example.example\_groups\_a, 其他随意
  59. 6. 保存
  60. 7. 点击中间的`动作`下拉框
  61. * 更改密码
  62. * 输入密码
  63. * 更改密码
  64. 3. 登录刚才新建的用户
  65. * 点击创建
  66. * 是不是发现select没有了, 哈哈哈哈哈哈
  1. 给name整个sequence

    • 新建文件夹addons/example/data
    • 新建文件addons/example/data/example_sequence.xml

    修改addons/example/data/example_sequence.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <odoo>
  3. <!--
  4. 年代: %(year)s
  5. 年份: %(y)s
  6. 月: %(month)s
  7. 日: %(day)s
  8. 某年某日: %(doy)s
  9. 某年某周: %(woy)s
  10. 某周某天 (0:周一): %(weekday)s
  11. 时 00->24: %(h24)s
  12. 时 00->12: %(h12)s
  13. 分: %(min)s
  14. 秒: %(sec)s
  15. -->
  16. <record id="example_sequence" model="ir.sequence">
  17. <field name="name">example.example</field>
  18. <field name="code">example.example</field>
  19. <field name="prefix">OUT%(year)s%(month)s%(day)s</field>
  20. <!--序列大小-->
  21. <field name="padding">4</field>
  22. <field name="company_id" eval="False"/>
  23. </record>
  24. </odoo>
  25. * 将文件路径添加到\_\_manifest\_\_.py中
  26. 'data': [ 'data/example_sequence.xml', ...
  27. * 修改addons/example/models/models.py
  28. ... name = fields.Char(default=lambda self: self.env['ir.sequence'].next_by_code(self._name)) ...
  29. * 重复步骤4
  30. * 此时会发现新建数据时. 会自动生成name
  1. 继承mail模块

    • 修改__manifest__.py

      1. ... 'depends': ['base', 'mail'], ...
    • 重启odoo后, 查看example应用信息的技术数据, 可以发现依赖多了个mail

    修改addons/example/models/models.py

  1. ... _inherit = ['mail.thread'] my_datetime = fields.Datetime(default=fields.Datetime.now, track_visibility='onchange') # my_date = fields.Date(default=fields.Date.today) my_date = fields.Date(default=lambda self: datetime.date.today() + datetime.timedelta(days=4), track_visibility='always' ) def button4(self): # 通过用户test的id, 实现点击关注用户test, # 获取id方法设置->用户&公司->test->相关的业务伙伴->test 查看当前URL id self.message_subscribe(partner_ids=[7]) def button5(self): # 点击添加备注 self.message_post(body='emmm') ...
  2. 修改addons/example/views/views.xml文件
  3. ...
  4. <field name="arch" type="xml">
  5. <form>
  6. <div class="oe_chatter">
  7. <field name="message_follower_ids" widget="mail_followers"/>
  8. <field name="message_ids" widget="mail_thread"/>
  9. </div>
  10. <header>
  11. ...
  12. <button states="3" name="button1" string="当前状态值为3, 点击设置为1" class="oe_highlight" type="object"/>
  13. <button name="button4" string="老铁, 点个关注" class="oe_highlight" type="object"/>
  14. <button name="button5" string="emmm" class="oe_highlight" type="object"/>
  15. <field name="state" widget="statusbar" statusbar_visible="1,2,3"/>
  16. ...
  17. * track\_visibility
  18. > 记录到备注中
  19. * track\_visibility='onchange' :修改该字段时记录
  20. * track\_visibility='always': 编辑track\_visibilityonchangealways对应的字段时记录
  21. * track\_visibility='always', odoo12.0 不可用时参考: https://www.cnblogs.com/edhg/p/11434625.html
  22. * 重复步骤4
  23. * 此时会发现多了块区域显示备注啥的
  1. 重载系统方法
    修改addons/example/models/models.py
  1. ... @api.onchange('active') def onchange_active(self): # 修改记录的active字段时, 设置note内容 self.update(dict(note='你敢改我active, 我就敢改我自己!')) def unlink(self): # 重写系统删除记录函数 for order in self: if len(order.name) > 10: raise UserError('这谁起的名字这么长, 俺不愿意删, 改短点!!!') return super().unlink() @api.model def create(self, vals): # 新建记录后, 点击保存后执行 # 很奇怪的地方就是float, int类型设定的默认值, 没有获取到 return super().create(vals) def write(self, vals): # 修改记录后, 点击保存后执行, vals包括被修改后的值 # 修改name后: vals = {'name': 'OUT201908sa300012asooss'} return super().write(vals) ...
  2. * onchange: 修改指定字段时执行
  3. * unlink: 删除数据(记录)时执行
  4. * create: 创建数据(记录)时执行
  5. * write: 修改数据(记录)`后`执行
  6. * 重复步骤4
  1. 计算字段

    会自动计算的字段

    修改addons/example/models/models.py

  1. ... name_and_price = fields.Char( compute='_compute_price_add_state_value' ) @api.depends('price', 'name') def _compute_price_add_state_value(self): # 添加计算字段 for order in self: order.name_and_price = '{} {}'.format(order.name, order.price) @api.onchange('price', 'name') def change_price_add_state_value(self): # 修改时,自动更新计算字段 self.update(dict( name_and_price='{} {}'.format(self.name, self.price) )) ...
  2. 修改addons/example/views/views.xml文件
  3. ...
  4. <record model="ir.ui.view" id="example.list">
  5. <field name="name">列表显示字段</field>
  6. <field name="model">example.example</field>
  7. <field name="arch" type="xml">
  8. <tree>
  9. <field name="name_and_price"/>
  10. ...
  11. <field name="select" required="0"/>
  12. <field name="name_and_price"/>
  13. </group>
  14. ...
  15. 重复步骤4
  1. 关系字段

    将当前字段绑定到某个字段, 值随之变化, 可选择存或不存到数据库

    修改addons/example/models/models.py

  1. ... # store: 是否把关联字段存到数据库 my_related1 = fields.Integer(related='em1_mo.fuck_id', string='关联到em1_mo.fuck_id', store=True) my_related2 = fields.Date(related='my_date', string='关联到my_date', store=True) ...
  2. 修改addons/example/views/views.xml文件
  3. ... <record model="ir.ui.view" id="example.list"> <field name="name">列表显示字段</field> <field name="model">example.example</field> <field name="arch" type="xml"> <tree> <field name="my_related1"/> <field name="my_related2"/> ... <field name="name_and_price"/> <field name="my_related1"/> <field name="my_related2"/> </group> ...
  4. 重复步骤4
  1. 查看模型, 菜单等

    • 点击设置
    • 点击技术
  2. 项目地址:https://github.com/dhgdhg/odoo-tutorial
  3. controller 回头再更

转载于:https://www.cnblogs.com/edhg/p/11444916.html

发表评论

表情:
评论列表 (有 0 条评论,348人围观)

还没有评论,来说两句吧...

相关阅读

    相关 文章了解Netty

    Netty 传统的IO模型的web容器,比如老版本的Tomcat,为了增加系统的吞吐量,需要不断增加系统核心线程数量,或者通过水平扩展服务器数量,来增加系统处理请求的能力

    相关 文章入门音视频

    一、概述 1)流媒体协议是服务器与客户端之间通信遵循的规定。当前网络上主要的流媒体协议如表所示。 2)封装格式的主要作用是把视频码流和音频码流按照一定的格式存储在一个文件中