博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一篇文章带你入门odoo
阅读量:5359 次
发布时间:2019-06-15

本文共 20065 字,大约阅读时间需要 66 分钟。

  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

        # -*- 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',    ],}

  4. 安装应用
    1. 重启odoo服务
    2. 点击刷新本地模型列表
    3. 弹出窗口点击更新按钮
    4. 删除搜索框内容,然后输入example
    5. 点击安装
      • 以后执行步骤4时, 点击三个小点点. 然后点击升级按钮
  5. 新建模型

    修改addons/example/models/models.py

    # -*- coding: utf-8 -*-import datetimefrom odoo import models, fields, apiclass 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')

    知识内容

    • 模型的字段
      • 系统字段
        • _name
          • 必需的
          • 定义了Odoo系统中模型的名称
        • _description
          • 为模型添加更为友好的描述,更新后在Settings下可发现相应的变化(需开启调试模式Database Structure>Models)
        • _order
          • 默认情况下Odoo使用内置的id进行排序,可以通过逗号分隔指定多个字段进行排序,desc表示降序,仅能使用数据库中存储的字段排序,外部计算后的字段不适用,_order有些类似SQL语句中的ORDER BY,但无法使用NULL FIRST之类的语句
        • 字段共同属性
          • string(unicode, 默认:字段名称)
            • UI中字段的标签(用户可见)
          • required(bool默认:False)
            • 如果True该字段不能为空, 则它必须具有默认值或在创建记录时始终给定值
          • help(unicode默认:'')
            • 长格式, 在UI中为用户提供帮助工具提示
          • index(bool默认:False)
            • 请求Odoo 在列上创建数据库索引
          • readonly(bool默认:False)
            • 是否只读
      • Model字段类型
        • 字段共同属性
          • string(unicode, 默认:字段名称)
            • UI中字段的标签(用户可见)
          • required(bool默认:False)
            • 如果True该字段不能为空, 则它必须具有默认值或在创建记录时始终给定值
          • help(unicode默认:'')
            • 长格式, 在UI中为用户提供帮助工具提示
          • index(bool默认:False)
            • 请求Odoo 在列上创建数据库索引
          • readonly(bool默认:False)
            • 是否只读
        • 常用字段属性
          • default
            • 默认值
        • Binary
          • Binary字段用于存储二进制文件,如图片或文档
          • a = fields.Binary()
        • Float
          • Float用于存储数值,其精度可以通过数字长度和小数长度一对值来进行指定
          a = fields.Float(    string='float',    digits=(14, 4), # Optional precision (total, decimals)    )
        • Boolean
          • Boolean字段用于存储True/False布尔值
          • a = fields.Boolean()
        • Integer
          • Integer即为整型
          • a = fields.Integer()
        • Char
          • Char用于字符串
          • a = fields.Char(string='aa', required=True)
        • Date
          • Date字段用于存储日期,ORM中以字符串格式对其进行处理,但以日期形式存放在数据库中,该格式在odoo.fileds.DATE_FORMAT中定义
          • my_date = fields.Date(default=fields.Date.today)
          • my_date = fields.Date(default=lambda self: datetime.date.today() + datetime.timedelta(days=4))
        • Datetime
          • Datetime用于存储日期时间,在数据库中以UTC无时区时间(naive)存放,ORM中以字符串和UTC时间表示,该格式在odoo.fields.DATETIME_FORMAT中定义
          • my_datetime = fields.Datetime(default=fields.Datetime.now)
        • Text
          • Text用于多行字符串
          • notes = fields.Text()
        • Monetary
          • 货币
          • a=fields.Monetary()
        • Html
          • Used to store HTML, provides an HTML widget.
          • Html类似text字段,但一般用于存储富文本格式的HTML
          • strip_style=True:清除所有样式元素
          • strip_class=True:清除类属性
          • description = fields.Html()
        • Selection
          • 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
          • Selection用于选择列表,由值和描述对组成,选择的值将存储在数据库中,可以为字符串或整型,描述默认可翻译,虽然整型的值看似简洁,但注意Odoo会把0解析为未设置(unset),因而当存储值为0时不会显示描述
          • index: Tells Odoo to index for faster searches replaces the select kwarg
          select = fields.Selection([    ('1', 'em'),    ('2', 'emm'),    ('3', 'emmm'),], required=True, default='1')
        • Many2one
          • Store a relation against a co-model
          • comodel_name指定绑定多对一的模型名, 即类名
          • em1_mo = fields.Many2one(comodel_name='example.example1')
        • Many2many
          • Store a relation against many2many rows of co-model
          • Many2many会新建一个中间表, relation指定中间表的表名
          • 例:
            python _name = 'emm.a' e = Many2many( comodel_name='emmm.b', # 关联的表 relation='emmm_a_b_rel', # 可选, 中间表名 column1='a_id', # 当前表的字段名 column2='b_id', # 关联的其他表的字段名 string='Tags')
        • One2many
          • Store a relation against many rows of co-model
          • 新建one2many前需要先写many2one, 并且数据库的外键会建立在many2one上
          • comodel_name: 指定绑定一对多的模型名, 即类名
          • inverse_name: 指定绑定一对多的模型的Many2one字段的名
          • domain
            • 过滤, 例:domain=[('id','=',1)]
            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')
        • Reference
          • Store an arbitrary reference to a model and a row
          • 事先不能决定关联的目标模型时, 这种情况需要使用reference将目标模型的选择权留给用户
          my_reference = fields.Reference(selection='_select_objects')@api.modeldef _select_objects(self):    records = self.env['ir.model'].search([])    return [(record.model, record.name) for record in records] + [('', '')]
      • 保留字段
        • Odoo在所有模型中都创建了以下几个字段,这些字段由系统管理,是系统保留的字段, 用户不应定义
          • id(Id)
            • 模型中记录的唯一标识符
          • create_date(Datetime)
            • 记录的创建日期
          • create_uid(Many2one)
            • 创建记录的用户
          • write_date(Datetime)
            • 记录的最后修改日期
          • write_uid(Many2one)
            • 上次修改记录的用户
      • Method and decorator
        • @api.returns
          • This decorator guaranties unity of returned value. It will return a RecordSet of specified model based on original returned value:
          @api.returns('res.partner')def afun(self):    ...    return x  # a RecordSet
        • @api.one
          • This decorator loops automatically on Records of RecordSet for you. Self is redefined as current record:
          @api.onedef afun(self):    self.name = 'toto'
        • @api.multi
          • Self will be the current RecordSet without iteration. It is the default behavior:
          @api.multidef afun(self):    len(self)
        • @api.model
          • This decorator will convert old API calls to decorated function to new API signature. It allows to be polite when migrating code.
          @api.modeldef afun(self):    pass
        • @api.constrains
          • 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.
        • @api.depends
          • 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
          @api.depends('name', 'an_other_field')def afun(self):    pass
        • @api.onchange
          • This decorator will trigger the call to the decorated function if any of the fields specified in the decorator is changed in the form
          @api.onchange('fieldx')def do_stuff(self):    if self.fieldx == x:        self.fieldy = 'toto'
        • @api.noguess
          • This decorator prevent new API decorators to alter the output of a method
  6. 升级应用
    1. 重启odoo服务
    2. 在搜索框输入example
    3. 点击升级
  7. 修改数据文件

    修改addons/example/views/views.xml文件

    example模型表头
    example.example
    example act_window
    example.example
    tree,form
    example server
    code
    action = { "type": "ir.actions.act_window", "view_mode": "tree,form", "res_model": "example.example", }

    重复步骤4 升级应用

    知识内容

    • 数据文件仅在安装或更新模块时才加载数据文件的内容
    • 模块的数据通过带有<record>元素的数据文件, XML文件声明.每个<record>元素都创建或更新数据库记录
    • 数据文件必须在要manifest文件中声明数据文件, 它们可以在data列表(始终加载)或demo列表中声明(仅在演示模式下加载).
    • 属性
      • model
        • 记录的Odoo模块的名称
      • id
        • 一个外部标识符, 用于被引用
      • <field>
        • name标识字段名称
        • <field>的innnerText是<field>的值
    • menuitem
      • 必须先声明相应的Action, 因为数据文件按顺序执行, 在id创建菜单之前, Action必须存在于数据库中
      • 在创建完菜单后必须成为超级用户才能正常显示新建的菜单
      • menuitem 只有绑定action, 或子menuitem绑定了action才能显示出来
      • 属性
        • id: 定义唯一标记
        • action: 绑定动作
        • parent: 父菜单
        • sequence: 优先级, 数字越小优先级越高, 显示越靠前,最小为0
        • groups: 绑定权限
        • name: 菜单名称
    • view
      • 视图定义了模块记录的显示方式(Views define the way the records of a model are displayed).每种类型的视图代表一种可视化模式(记录列表, 其聚合图, ......).可以通过类型(例如合作伙伴列表)或特别是通过其ID 来一般性地请求视图.对于通用请求, 将使用具有正确类型和最低优先级的视图(因此每种类型的最低优先级视图是该类型的默认视图).

      • 对于view 中的<record>的id, 会被存到数据库中, 而且当你修改<record>的model, 然后再次执行, 则<record>的model仍为修改前的model, 不报错, 且正常使用
        • 解决方法:
          • 修改<record>的id
          • 或将<record>删除, 重启服务,升级模块, 然后再写<record>
  8. 自定义添加数据的表单

    修改addons/example/models/models.py

    # -*- coding: utf-8 -*-import datetimefrom odoo import models, fields, apiclass 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')

    修改addons/example/views/views.xml文件

    列表显示字段
    example.example
    ir.actions.act_window
    我会被显示出来
    example.example
    example.example

    重复步骤4: 升级应用

    知识内容

    • model="ir.ui.view"的recoder 不需要绑定任何只要在xml文件中出现既能正常显示
    • 视图被声明为ir.ui.view的Model的record.视图类型由arch字段的根元素声明

    • 表单视图
      • 属性
        • create="0": 不可新建
        • edit="0": 编辑
        • delete="0": 删除
      • field属性
        • widget
          • statusbar
            • 头部状态条标签
          • email
            • 电子邮件地址标签
          • selection
            • 下拉选择标签
          • mail_followers
            • 关注者标签
          • mail_thread
            • 消息标签
          • progressbar
            • 进度条,按百分比标签
          • one2many_list
            • 一对多列表标签
          • many2many_tags
            • 多对多显示标签
          • url
            • 网站链接标签
          • image
            • 图片标签
          • many2many_kanban
            • 看版标签
          • handler
            • 触发标签
          • radio
            • 单选标签
          • char_domain
            • 字符域标签
          • monetary
            • 价格(和精度位数相关)标签
          • float_time
            • 单精度时间标签
          • html
            • html相关标签
          • pad
            • pad显示相关标签
          • date
            • 日期标签
          • monetary
            • 金额标签
          • text
            • 文本标签
          • sparkline_bar
            • 燃尽标签
          • checkbox
            • 复选框标签
          • reference
            • 关联标签
        • required
          • 必填
        • readonly
          • 只读
        • invisible
          • 不可见
        • 根据条件变化
          • name='123'invisible="1"
          • active=Truerequired="1"
          • 当前字段不是'many2many', 'many2one'状态时readonly="1"
          attrs="{    'invisible':[('name','=','123')],    'required':[('active','=', True)],    'readonly':[('ttype','not in', ['many2many', 'many2one'])]        }"
        • 过滤one2many, many2many, 后面的many
          • domain
          • domain="[('id','=',1)]"

      表单视图还可以使用纯HTML来实现更灵活的布局

    • 树视图

      树视图(也称为列表视图)以表格形式显示记录.他的根元素是<tree>.最简单的树形视图, 即只需列出要在表中显示的所有字段(每个字段作为列)

      • 属性
        • create="0": 不可新建
        • edit="0": 编辑
        • delete="0": 删除
    • 搜索视图

      搜索视图通过列表视图(以及其他聚合视图)自定义关联的搜索字段.他的根元素是<search>, 他包含的字段, 定义了哪些时用于搜索的字段

      course.search
      openacademy.course

      • 如果模块不存在搜索视图, 则Odoo会生成仅允许在该name字段上搜索的视图.
  9. 权限管理

    添加文件addons/em/security/security.xml

    example.example_category
    example.example_groups_a
    example.example_groups_b

    修改addons/example/__manifest__.py

    ...# always loaded# 数据文件'data': [    'security/security.xml',    'views/views.xml',    'views/templates.xml',],...

    • 两种方法设置字段指定用户组可见

      法一. 修改addons/example/models/models.py

      ...# 设置example.example_groups_b组的用户可见select = fields.Selection([    ('1', 'em'),    ('2', 'emm'),    ('3', 'emmm'),], groups="example.example_groups_b")...

      法二. 修改addons/example/views/views.xml

      xml ... <field name="select" required="0" groups="example.example_groups_b"/> ...

      个人推荐法一

      example act_window
      example.example
      tree,form

    • 重复步骤4: 升级应用

    • 验证权限
      1. 修改群组访问权限
        1. 设置
        2. 用户&公司
        3. 群组
        4. 点击 example.example_category / example.example_groups_a
          1. 编辑
          2. 访问权限
          3. 添加明细行
            • 名称随意
            • 对象, 点击搜索更多后搜索并选择example.example
            • 读, 写, 创建, 删除权限都勾上
          4. 添加明细行
            • 名称随意
            • 对象, 点击搜索更多后搜索并选择example.example1
            • 读, 写, 创建, 删除权限都勾上
          5. 保存
      2. 新建用户
        1. 设置
        2. 用户&公司
        3. 用户
        4. 创建
        5. example.example_category 选择 example.example_groups_a, 其他随意
        6. 保存
        7. 点击中间的动作下拉框
          • 更改密码
            • 输入密码
            • 更改密码
      3. 登录刚才新建的用户
        • 点击创建
        • 是不是发现select没有了, 哈哈哈哈哈哈
  10. 给name整个sequence
    • 新建文件夹addons/example/data
    • 新建文件addons/example/data/example_sequence.xml

    修改addons/example/data/example_sequence.xml

    example.example
    example.example
    OUT%(year)s%(month)s%(day)s
    4
    • 将文件路径添加到__manifest__.py中
    'data': [    'data/example_sequence.xml',...
    • 修改addons/example/models/models.py

      ...name = fields.Char(default=lambda self: self.env['ir.sequence'].next_by_code(self._name))...
    • 重复步骤4
    • 此时会发现新建数据时. 会自动生成name

  11. 继承mail模块
    • 修改__manifest__.py

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

    修改addons/example/models/models.py

    ..._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')...

    修改addons/example/views/views.xml文件

    ...
    ...
    ...
    • track_visibility

      记录到备注中

      • track_visibility='onchange' :修改该字段时记录
      • track_visibility='always': 编辑track_visibility为onchange或always对应的字段时记录
        • track_visibility='always', odoo12.0 不可用时参考: https://www.cnblogs.com/edhg/p/11434625.html
    • 重复步骤4
      • 此时会发现多了块区域显示备注啥的
  12. 重载系统方法

    修改addons/example/models/models.py

    ...@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.modeldef create(self, vals):    # 新建记录后, 点击保存后执行    # 很奇怪的地方就是float, int类型设定的默认值, 没有获取到    return super().create(vals)def write(self, vals):    # 修改记录后, 点击保存后执行, vals包括被修改后的值    # 修改name后: vals = {'name': 'OUT201908sa300012asooss'}    return super().write(vals)...
    • onchange: 修改指定字段时执行
    • unlink: 删除数据(记录)时执行
    • create: 创建数据(记录)时执行
    • write: 修改数据(记录)执行
    • 重复步骤4
  13. 计算字段

    会自动计算的字段

    修改addons/example/models/models.py

    ...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)    ))...

    修改addons/example/views/views.xml文件

    ...
    列表显示字段
    example.example
    ...
    ...

    重复步骤4

  14. 关系字段

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

    修改addons/example/models/models.py

    ...# 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)...

    修改addons/example/views/views.xml文件

    ...
    列表显示字段
    example.example
    ...
    ...

    重复步骤4

  15. 查看模型, 菜单等
    • 点击设置
    • 点击技术
  16. 项目地址:https://github.com/dhgdhg/odoo-tutorial
  17. controller 回头再更

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

你可能感兴趣的文章
动态内存申请函数选择(realloc、malloc 、alloca、 calloc)
查看>>
获取元素属性get_attribute
查看>>
视觉设计师的进化
查看>>
Python/jquery
查看>>
【BZOJ】【2132】圈地计划
查看>>
Lua 语言基本语法
查看>>
ARM 的Thumb状态测试
查看>>
windows下读取utf-8文件
查看>>
apache 启动不了的排查方法
查看>>
Java有没有goto?
查看>>
(转)makefile 的用法
查看>>
求不相邻金币相加和的最大值--动态规划1
查看>>
[转][osg]探索未知种族之osg类生物【目录】
查看>>
四十九. Zabbix报警机制 、 Zabbix进阶操作 、 监控案例
查看>>
元类中__new__ 与 __init__的区别--day27
查看>>
占小狼的简书博客
查看>>
struts2__action执行顺序
查看>>
php异常处理
查看>>
[xampp] /usr/bin/env: php: No such file or directory
查看>>
细学PHP 10 贴吧-2
查看>>