-
激活開發者模式
- 點擊設置(點下左上角的四個小方塊, 就能看到)
- 點擊頁面右側的激活開發者模式
-
成為超級用戶
- 點擊右上方開發者工具(小蟲子按鈕)
- 點擊成為超級用戶
-
創建應用
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', ], } - controllers
-
-
安裝應用
- 重啟odoo服務
- 點擊
刷新本地模型列表 - 彈出窗口點擊
更新按鈕 - 刪除搜索框內容,然后輸入
example - 點擊安裝
- 以后執行步驟4時, 點擊三個小點點. 然后點擊升級按鈕
-
新建模型
修改addons/example/models/models.py # -*- 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')知識內容 - 模型的字段
-
系統字段
_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)
- 是否只讀
- string(unicode, 默認:字段名稱)
-
Model字段類型
-
字段共同屬性
- string(unicode, 默認:字段名稱)
- UI中字段的標簽(用戶可見)
- required(bool默認:False)
- 如果True該字段不能為空, 則它必須具有默認值或在創建記錄時始終給定值
- help(unicode默認:'')
- 長格式, 在UI中為用戶提供幫助工具提示
- index(bool默認:False)
- 請求Odoo 在列上創建數據庫索引
- readonly(bool默認:False)
- 是否只讀
- string(unicode, 默認:字段名稱)
-
常用字段屬性
- default
- 默認值
- 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指定中間表的表名
- 例:
_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.model def _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)
- 上次修改記錄的用戶
- id(Id)
- Odoo在所有模型中都創建了以下幾個字段,這些字段由系統管理,是系統保留的字段, 用戶不應定義
-
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.one def afun(self): self.name = 'toto' - @api.multi
- Self will be the current RecordSet without iteration. It is the default behavior:
@api.multi def 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.model def 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
- @api.returns
-
- 模型的字段
-
升級應用
- 重啟odoo服務
- 在搜索框輸入
example - 點擊升級
-
修改數據文件
修改addons/example/views/views.xml文件 <odoo> <data> <!-- explicit list view definition --> <!--選擇顯示哪些字段, 默認是name,即ui--> <record model="ir.ui.view" id="example.list"> <field name="name">example模型表頭</field> <field name="model">example.example</field> <field name="arch" type="xml"> <tree> <field name="name"/> <field name="active"/> <field name="price"/> </tree> </field> </record> <!-- actions opening views on models --> <!--選擇哪些功能動作即action--> <!--res_model是目標模塊的標識符 --> <record model="ir.actions.act_window" id="example.action_window"> <field name="name">example act_window</field> <field name="res_model">example.example</field> <!-- tree, 顯示數據 form, 新建數據 默認為tree --> <field name="view_mode">tree,form</field> </record> <!-- server action to the one above --> <!--執行py代碼--> <record model="ir.actions.server" id="example.action_server"> <field name="name">example server</field> <field name="model_id" ref="model_example_example"/> <field name="state">code</field> <!-- <field name="code">里面包裹的是py代碼 action將作為下一個要執行的操作返回給客戶端 --> <field name="code"> action = { "type": "ir.actions.act_window", "view_mode": "tree,form", "res_model": "example.example", } </field> </record> <!-- Top menu item --> <!--頂部菜單--> <menuitem name="example" id="example.menu_root"/> <!-- menu categories --> <!--分菜單--> <menuitem name="Menu 1" id="example.menu_1" parent="example.menu_root"/> <menuitem name="Menu 2" id="example.menu_2" parent="example.menu_root"/> <!-- actions --> <!--菜單綁定動作--> <menuitem name="List" id="example.menu_1_list" parent="example.menu_1" action="example.action_window"/> <menuitem name="Server to list" id="example" parent="example.menu_2" action="example.action_server"/> </data> </odoo>重復步驟4 升級應用
知識內容 -
數據文件僅在安裝或更新模塊時才加載數據文件的內容
-
模塊的數據通過帶有
<record>元素的數據文件, XML文件聲明.每個<record>元素都創建或更新數據庫記錄 -
數據文件必須在要manifest文件中聲明數據文件, 它們可以在
data列表(始終加載)或demo列表中聲明(僅在演示模式下加載). -
屬性
- model
- 記錄的Odoo模塊的名稱
- id
- 一個外部標識符, 用於被引用
<field>- name標識字段名稱
<field>的innnerText是<field>的值
- model
-
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>
- 修改
- 解決方法:
-
-
-
自定義添加數據的表單
修改addons/example/models/models.py # -*- 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')修改addons/example/views/views.xml文件 重復步驟4: 升級應用<odoo> <data> <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="name"/> <field name="active"/> <field name="price"/> <field name="note"/> <field name="content"/> <field name="my_date"/> <field name="my_datetime"/> <field name="select"/> <field name="em1_mo"/> <field name="em1_om"/> <field name="em1_mm"/> <field name="my_reference"/> </tree> </field> </record> <!--動作--> <record id="example.root_menu_action_view" model="ir.actions.act_window"> <field name="type">ir.actions.act_window</field> <field name="name">我會被顯示出來</field> <field name="res_model">example.example</field> </record> <!--自定義form表單--> <record id="example.example_form_view" model="ir.ui.view"> <field name="model">example.example</field> <field name="arch" type="xml"> <form> <header> <!--三個按鈕, 一個狀態條--> <!-- - button - name: 點擊時執行的函數名 - string: 按鈕顯示內容 - states: 當狀態值為多少時, 該按鈕可見, 不設置則永遠可見 - <field name="state" widget="statusbar"/> - statusbar_visible: 根據state值確定哪些狀態在狀態條上顯示 --> <button states="1" name="button2" string="當前狀態值為1, 點擊設置為2" class="oe_highlight" type="object"/> <button states="1" name="button3" string="當前狀態值為1, 點擊設置為3" class="oe_highlight" type="object"/> <button states="2" name="button3" string="當前狀態值為2, 點擊設置為3" class="oe_highlight" type="object"/> <button states="3" name="button1" string="當前狀態值為3, 點擊設置為1" class="oe_highlight" type="object"/> <field name="state" widget="statusbar" statusbar_visible="1,2,3"/> </header> <sheet> <group string="group1"> <field name="name"/> <field name="active"/> <field name="price" readonly="1"/> </group> <group string="group2"> <field name="my_datetime" attrs="{'invisible': [('active', '=', False)]}"/> <!-- 此處的required的優先級大於models中的required, 但是提交時會彈錯 --> <field name="my_date" required="1"/> <field name="select" required="0"/> </group> <group string="group3"> <field name="em1_mo"/> <field name="em1_om"/> <field name="em1_mm"/> <field name="my_reference"/> </group> <notebook string="notebook1"> <page string="page1"> <field name="note"/> </page> <page string="page1"> <field name="content"/> </page> </notebook> </sheet> </form> </field> </record> <menuitem id="example.root_menu" name="example" action="example.root_menu_action_view" sequence="1"/> </data> </odoo>知識內容 -
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
- 關聯標簽
- statusbar
required- 必填
readonly- 只讀
invisible- 不可見
- 根據條件變化
name='123'時invisible="1"active=True時required="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)]"
- widget
表單視圖還可以使用純HTML來實現更靈活的布局
<form string="Idea Form"> <header> <button string="Confirm" type="object" name="action_confirm" states="draft" class="oe_highlight" /> <button string="Mark as done" type="object" name="action_done" states="confirmed" class="oe_highlight"/> <button string="Reset to draft" type="object" name="action_draft" states="confirmed,done" /> <field name="state" widget="statusbar"/> </header> <sheet> <div class="oe_title"> <label for="name" class="oe_edit_only" string="Idea Name" /> <h1><field name="name" /></h1> </div> <separator string="General" colspan="2" /> <group colspan="2" col="2"> <field name="description" placeholder="Idea description..." /> </group> </sheet> </form> - 屬性
-
樹視圖
樹視圖(也稱為列表視圖)以表格形式顯示記錄.他的根元素是
<tree>.最簡單的樹形視圖, 即只需列出要在表中顯示的所有字段(每個字段作為列)-
屬性
- create="0": 不可新建
- edit="0": 編輯
- delete="0": 刪除
<tree string="Idea list"> <field name="name"/> <field name="inventor_id"/> </tree>
-
-
搜索視圖
搜索視圖通過列表視圖(以及其他聚合視圖)自定義關聯的搜索字段.他的根元素是
<search>, 他包含的字段, 定義了哪些時用於搜索的字段<search> <field name="name"/> <field name="inventor_id"/> </search>例
</field> </record> <record model="ir.ui.view" id="course_search_view"> <field name="name">course.search</field> <field name="model">openacademy.course</field> <field name="arch" type="xml"> <search> <field name="name"/> <field name="description"/> </search> </field> </record>- 如果模塊不存在搜索視圖, 則Odoo會生成僅允許在該name字段上搜索的視圖.
-
-
權限管理
添加文件addons/em/security/security.xml <?xml version="1.0" encoding="UTF-8" ?> <odoo> <record id="example.example_category" model="ir.module.category"> <field name="name">example.example_category</field> <field name="sequence" eval="1"/> </record> <record id="example.example_groups_a" model="res.groups"> <field name="name">example.example_groups_a</field> <field name="category_id" ref="example.example_category"/> <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/> </record> <record id="example.example_groups_b" model="res.groups"> <field name="name">example.example_groups_b</field> <field name="category_id" ref="example.example_category"/> <!--example.example_groups_a和example.example_groups_b, 只能選一個--> <field name="implied_ids" eval="[(4, ref('example.example_groups_a'))]"/> <!--example.example_groups_a和example.example_groups_b, 可以同時選--> <!--<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>--> </record> </odoo>修改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
... <field name="select" required="0" groups="example.example_groups_b"/> ...個人推薦法一 <record model="ir.actions.act_window" id="example.action_window"> <field name="name">example act_window</field> <field name="res_model">example.example</field> <field name="view_mode">tree,form</field> <!-- 在model中設置groups后, 會自動權限管理 --> </record> -
重復步驟4: 升級應用
-
驗證權限
-
修改群組訪問權限
- 設置
- 用戶&公司
- 群組
- 點擊
example.example_category / example.example_groups_a- 編輯
- 訪問權限
- 添加明細行
- 名稱隨意
- 對象, 點擊搜索更多后搜索並選擇
example.example - 讀, 寫, 創建, 刪除權限都勾上
- 添加明細行
- 名稱隨意
- 對象, 點擊搜索更多后搜索並選擇
example.example1 - 讀, 寫, 創建, 刪除權限都勾上
- 保存
-
新建用戶
- 設置
- 用戶&公司
- 用戶
- 創建
- example.example_category 選擇 example.example_groups_a, 其他隨意
- 保存
- 點擊中間的
動作下拉框- 更改密碼
- 輸入密碼
- 更改密碼
- 更改密碼
-
登錄剛才新建的用戶
- 點擊創建
- 是不是發現select沒有了, 哈哈哈哈哈哈
-
-
-
給name整個sequence
- 新建文件夾
addons/example/data - 新建文件
addons/example/data/example_sequence.xml
修改addons/example/data/example_sequence.xml <?xml version="1.0" encoding="utf-8"?> <odoo> <!-- 年代: %(year)s 年份: %(y)s 月: %(month)s 日: %(day)s 某年某日: %(doy)s 某年某周: %(woy)s 某周某天 (0:周一): %(weekday)s 時 00->24: %(h24)s 時 00->12: %(h12)s 分: %(min)s 秒: %(sec)s --> <record id="example_sequence" model="ir.sequence"> <field name="name">example.example</field> <field name="code">example.example</field> <field name="prefix">OUT%(year)s%(month)s%(day)s</field> <!--序列大小--> <field name="padding">4</field> <field name="company_id" eval="False"/> </record> </odoo>- 將文件路徑添加到__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
- 新建文件夾
-
繼承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文件 ... <field name="arch" type="xml"> <form> <div class="oe_chatter"> <field name="message_follower_ids" widget="mail_followers"/> <field name="message_ids" widget="mail_thread"/> </div> <header> ... <button states="3" name="button1" string="當前狀態值為3, 點擊設置為1" class="oe_highlight" type="object"/> <button name="button4" string="老鐵, 點個關注" class="oe_highlight" type="object"/> <button name="button5" string="emmm" class="oe_highlight" type="object"/> <field name="state" widget="statusbar" statusbar_visible="1,2,3"/> ...- 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
- 此時會發現多了塊區域顯示備注啥的
-
-
重載系統方法
修改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.model def 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
-
計算字段
會自動計算的字段
修改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文件 ... <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="name_and_price"/> ... <field name="select" required="0"/> <field name="name_and_price"/> </group> ...重復步驟4
-
關系字段
將當前字段綁定到某個字段, 值隨之變化, 可選擇存或不存到數據庫
修改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文件 ... <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
-
查看模型, 菜單等
- 點擊設置
- 點擊技術
-
controller 回頭再更
