向?qū)?/h4>
向?qū)б詣討B(tài)形式描述與用戶(或?qū)υ捒颍┑慕换ナ綍挕O驅(qū)c其他的模型不同,其基類是TransientModel
而不是常見的Model
。TransientModel
類擴展自Model
,并使用了其所有機制,具有以下特殊性:
- 向?qū)в涗洸皇怯谰眯缘模瑫谝欢螘r間后自動從數(shù)據(jù)庫中刪除。這就是為什么他們被稱為瞬態(tài)。
- 向?qū)P筒恍枰L問權(quán)限:用戶擁有向?qū)в涗浀乃袡?quán)限
- 向?qū)в涗浛梢酝ㄟ^many2one字段引用普通記錄或向?qū)в涗洠胀ㄓ涗洘o法通過many2one引用向?qū)в涗洝?br> 我們要創(chuàng)建一個向?qū)В脕碜層脩艨梢陨墒谡n的參與者,或者一次創(chuàng)建一個授課列表。
練習(xí)定義向?qū)?br> 創(chuàng)建一個向?qū)P停@個向?qū)P屯ㄟ^many2one關(guān)聯(lián)授課模型,并通過many2many關(guān)聯(lián)合作伙伴模型。添加新文件
openacademy/wizard.py
openacademy/__init__.py
from . import controllers
from . import models
from . import partner
from . import wizard
openacademy/wizard.py
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class Wizard(models.TransientModel):
_name = 'openacademy.wizard'
session_id = fields.Many2one('openacademy.session',
string="Session", required=True)
attendee_ids = fields.Many2many('res.partner', string="Attendees")
啟動向?qū)?/h5>
向?qū)ㄟ^ir.actions.act_window
記錄來啟動,target
字段設(shè)置值為new
。后者將在一個彈出窗口中打開向?qū)А2僮骺梢杂胁藛雾椨|發(fā)。還有另外一種方式來啟動向?qū)В菏褂妙愃朴谏厦娴?code>ir.actions.act_window記錄,但有一個額外字段src_model
,指定那個模型的操作可用。該向?qū)⒊霈F(xiàn)在模型主視圖的上下文操作中。因為這是在ORM中的內(nèi)部鉤子,所以這個操作通過在XML文件的act_window
標(biāo)簽中進行定義。
<act_window id="launch_the_wizard"
name="Launch the Wizard"
src_model="context.model.name"
res_model="wizard.model.name"
view_mode="form"
target="new"
key2="client_action_multi"/>
向?qū)褂贸R?guī)視圖并且它的按鈕可以使用special="cancel"
來關(guān)閉向?qū)Т翱诙恍枰3帧?/p>
練習(xí)啟動向?qū)?/p>
- 為向?qū)Фx一個form視圖
- 在授課模型的上下文中添加action用于啟動向?qū)?/li>
- 給向?qū)У?em>session字段定義默認值;使用上下文參數(shù)
self._context
來獲取當(dāng)前授課
openacademy/wizard.py
class Wizard(models.TransientModel):
_name = 'openacademy.wizard'
def _default_session(self):
return self.env['openacademy.session'].browse(self._context.get('active_id'))
session_id = fields.Many2one('openacademy.session',
string="Session", required=True, default=_default_session)
attendee_ids = fields.Many2many('res.partner', string="Attendees")
openacademy/views/openacademy.xml
parent="openacademy_menu"
action="session_list_action"/>
<record model="ir.ui.view" id="wizard_form_view">
<field name="name">wizard.form</field>
<field name="model">openacademy.wizard</field>
<field name="arch" type="xml">
<form string="Add Attendees">
<group>
<field name="session_id"/>
<field name="attendee_ids"/>
</group>
</form>
</field>
</record>
<act_window id="launch_session_wizard"
name="Add Attendees"
src_model="openacademy.session"
res_model="openacademy.wizard"
view_mode="form"
target="new"
key2="client_action_multi"/>
</data>
</odoo>
練習(xí)注冊與會者
給向?qū)砑影粹o,并且實現(xiàn)相應(yīng)的方法,將與會者添加到給定的授課。
openacademy / views / openacademy.xml
<field name="attendee_ids"/>
</group>
<footer>
<button name="subscribe" type="object"
string="Subscribe" class="oe_highlight"/>
or
<button special="cancel" string="Cancel"/>
</footer>
</form>
</field>
</record>
openacademy/wizard.py
session_id = fields.Many2one('openacademy.session',
string="Session", required=True, default=_default_session)
attendee_ids = fields.Many2many('res.partner', string="Attendees")
@api.multi
def subscribe(self):
self.session_id.attendee_ids |= self.attendee_ids
return {}
練習(xí)與會者注冊多個授課
修改向?qū)P停员闩c會者可以注冊到多個授課
openacademy/views/openacademy.xml
<form string="Add Attendees">
<group>
<field name="session_ids"/>
<field name="attendee_ids"/>
</group>
<footer>
<button name="subscribe" type="object"
openacademy/wizard.py
class Wizard(models.TransientModel):
_name = 'openacademy.wizard'
def _default_sessions(self):
return self.env['openacademy.session'].browse(self._context.get('active_ids'))
session_ids = fields.Many2many('openacademy.session',
string="Sessions", required=True, default=_default_sessions)
attendee_ids = fields.Many2many('res.partner', string="Attendees")
@api.multi
def subscribe(self):
for session in self.session_ids:
session.attendee_ids |= self.attendee_ids
return {}
國際化
每個模塊都可以在i18n目錄提供自己的翻譯,文件名的形式為LANG.po,其中LANG是語言的代碼,或者是語言和國家的組合,例如:pt.po(葡萄牙語)和pt_BR.po(巴西葡萄牙語)。對于所有開啟的語言,Odoo都會自動載入翻譯。開發(fā)者總是使用英語建立模塊,然后使用Odoo的文本POT導(dǎo)出功能導(dǎo)出模塊術(shù)語(設(shè)置->翻譯->導(dǎo)入/導(dǎo)出->導(dǎo)出翻譯),生成模塊的POT模板文件,然后到處PO翻譯文件。許多IDE具有用于編輯和合并PO/POT文件的插件或功能。
提示
把Odoo生成的導(dǎo)出文件公布在Transifex,可以輕松的使用軟件進行翻譯。
|- idea/ # The module directory
|- i18n/ # Translation files
| - idea.pot # Translation Template (exported from Odoo)
| - fr.po # French translation
| - pt_BR.po # Brazilian Portuguese translation
| (...)
提示
默認情況下Odoo的POT導(dǎo)出僅提取XML文件的標(biāo)簽和Python代碼中的字段定義,但是任何Python字符串都可以翻譯,通過使用odoo._()
方法,例如_("Label")
。
練習(xí)
翻譯一個模塊
為已經(jīng)安裝的Odoo模塊選擇第二語言。使用Odoo提供的功能對模塊進行翻譯。
- 創(chuàng)建目錄
openacademy/i18n/
- 安裝任意一種你希望的語言 (設(shè)置->翻譯->加載翻譯 )
- 同步翻譯術(shù)語(設(shè)置->翻譯->應(yīng)用程序術(shù)語->同步術(shù)語)
- 導(dǎo)出不指定語言的翻譯模板文件(設(shè)置->翻譯->導(dǎo)入/導(dǎo)出->導(dǎo)出翻譯),保存在
openacademy/i18n/
- 導(dǎo)出指定語言的翻譯文件(設(shè)置->翻譯->導(dǎo)入/導(dǎo)出->導(dǎo)出翻譯),保存在
openacademy/i18n/
- 打開導(dǎo)出的翻譯文件(使用任意一款文本編輯軟件或者專用的PO文件編輯器,例如POEdit然后翻譯其中的術(shù)語)
- 在
models.py
文件中,為odoo._
方法添加一個導(dǎo)入聲明,并且標(biāo)記需要翻譯的字符串 - 重復(fù)3-6的步驟
openacademy/models.py
# -*- coding: utf-8 -*-
from datetime import timedelta
from odoo import models, fields, api, exceptions, _
class Course(models.Model):
_name = 'openacademy.course'
default = dict(default or {})
copied_count = self.search_count(
[('name', '=like', _(u"Copy of {}%").format(self.name))])
if not copied_count:
new_name = _(u"Copy of {}").format(self.name)
else:
new_name = _(u"Copy of {} ({})").format(self.name, copied_count)
default['name'] = new_name
return super(Course, self).copy(default)
if self.seats < 0:
return {
'warning': {
'title': _("Incorrect 'seats' value"),
'message': _("The number of available seats may not be negative"),
},
}
if self.seats < len(self.attendee_ids):
return {
'warning': {
'title': _("Too many attendees"),
'message': _("Increase seats or remove excess attendees"),
},
}
def _check_instructor_not_in_attendees(self):
for r in self:
if r.instructor_id and r.instructor_id in r.attendee_ids:
raise exceptions.ValidationError(_("A session's instructor can't be an attendee"))