示例:D:\env\python\python.exe D:\odoo-14\server\odoo-bin scafflod module_name D:\odoo- 14\server\addons
写法1: 找视图id,返回动作窗口字典,方法与视图示例如下:
def open_tree_or_form(self):
res_ids = self.env['qc.dmr'].sudo().search([('name', '=', '203382')])
tree_view_id = self.env.ref('xunde_quality_contorl.qc_dmr_tree_view')
form_view_id = self.env.ref('xunde_quality_control.qc_dmr_form_view')
if len(res_ids) == 1:
return {
'name' _(质检),
'view_mode': 'form',
'res_model': 'qc.dmr',
'views': [[form_view_id.id, 'form']],
'type': 'ir.actions.act_window',
'res_id': dmr_ids.id,
'target': 'current',
'context': {}
}
elif len(res_ids) > 1:
return {
'name' _(质检),
'view_mode': 'tree',
'res_model': 'qc.dmr',
'views': [(tree_view_id.id, 'tree'), (form_view_id.id, 'form')],
'type': 'ir.actions.act_window',
'domain': [('id', 'in', res_ids.ids)],
'target': 'current',
'context': {}
}
else:
return {'type': 'ir.actions.act_window_close'}
<...>
写法2:找特定action的id,并在方法里返回,示例代码如下:
def open_tree_or_form(self):
...
action = self.env['ir.actions.act_window']._for_xml_id(f"account.{action.name}")
action['context'] = {}
action['domain'] = [(...)]
action['name'] = _("...")
action['views'] = [[False, 'form']]
...
return action
用途:可以用于审批驳回功能,可以用于导入文件向导, 一般是在视图添加按钮,通过按钮打开瞬态视图,瞬态视图模型,一般有个default_get函数和关联主表的字段,示例代码如下:
...
# 瞬态模型示例
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class TransientModelExample(models.TransientModel):
_name = 'transientmodel.example'
_description = '瞬态模型示例'
def default_get(self, fields_list):
....
origin_id = fields.Many2one(...)
def action_reject(self):
...
利用xpath语法,对原有视图进行修改,不建议过多继承视图,因为会导致视图继承混乱,后期不好维护。
1
需求:打开tree视图,就有默认分组,修改搜索视图和客户端动作的上下文,示例代码如下:
...
...
tree,form
{'search_default_by_parent_id':1}
实现字段与按钮在一行,代码如下:
该函数是视图加载时会自动调用的函数,使用场景示例:根据权限组动态控制字段的属性,包括可见性、只读性等,示例代码如下:
@api.model
def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
result = super(XdBusinessExample,self)._fields_view_get(view_id=view_id,
view_type=view_type,
toolbar=toolbar,
submenu=submenu)
if view_type == 'form':
if self.env.user.has_group('xd.business.purchase_group'):
doc = etree.XML(result.get('arch', ''))
page_purchase = doc.xpath('page[@name='purchase']')
for i in page_purchase:
i.set('invisible', '1')
result['arch'] = etree.tostring(doc)
return result
需求:将明细中的bianry文件全部转化为附件存储,示例代码如下:
def binary_to_attachments(self):
documemnts = self.env['related.documents'].search([('assmenbly_id', '=',
self.assembly_id.id)])
files = []
for doc in documents:
attachment = self.env['ir.attacnment'].create({'datas': doc.file, 'name':
doc.filename})
files.appned((4, attachment.id))
self.attachment_ids = files
search_read函数是再打开tree、看板视图时自动触发的函数,可以重写该方法,以控制要显示的记录,示例代码如下:
@api.model
def search_read(self, domian=None, fields=None, offset=0, limit=80, order=None):
sql = ''' select row_number() over() as id,
model_name,
user_id,
count(*) as wait_approval_count,
string_agg(res_id || '', ',') as res_ids,
state
from wait_approval wher user_id = %s and state = '%s'
group by model_name, user_id, state''' %(self.env.user.id, state)
self.env.cr.excute(sql)
records = self.env.cr.fetchall()
vals = []
for r in records:
vals.append({'model_name': r[1], 'user_id': r[2]})
res.create(vals)
domain = [('id', 'in', res.ids)]
return super(XdSearchExample, self).search_read(domain=domain, fields=fields,
offset=offset, limit=limit,
order=order)
odoo框架自带的邮件通知模块mail.message ,示例代码如下:
def mail_message_example(self):
...
user_id = self.env['res.users'].search([('name', '=', 'xxx')], limit=1)
self.env['mail.message'].create({
'subject': '通知:xxx',
'model': xxx,
'res_id': self.id,
'record_name': xxx,
'body': u'有单据%s需要您审批' % sheet_name,
'partner_ids': [(6, 0, usre_id.partner_id.id)], # 收件人
'notification_ids': [(5, 0, 0), (0, 0, {'res_partner_id': user_id.partner_id.id,
'notification_type': 'inbox'})],
'subtype_id': self.env['ir.model.data'].xmlid_to_res_id('mail.mt_commet'),
'message_type': 'notification',
'author_id': self.env.user.partner_id.id,
'replay_to': False,
'email_from': False,
})
...
kanban写法示例如下:
利用ir.sequence模型实现,示例代码如下:
...
name = fields.Char(string='单号', default='New')
...
@api.model
def create(self, vals):
if vals.get('name', 'New') == 'New':
vals['name'] = self.env['ir.sequence'].next_by_code('customer.complaint.sheet') or
'/'
return super(XdSequenceExapmle, self).create(vals)
xxx
customer.complaint.sheet
CCS%(year)s%(month)s%(day)s
3
通常情况下,计算字段如果不存储在数据库中,是无法搜索的,但是可以指定字段的search属性,实现可搜索,示例代码如下;
...
saleman = fields.Many2one('res.users', compute='xxx', string='业务员',
search='_search_saleman_example)
...
def xxx(self):
todo
...
def _search_saleman_example(self, operator, value):
ids = []
mrps = self.env['mrp'].search([])
users = self.env['res.users'].search([('name', '=', value)]
for r in mrps:
if r.saleman.id in users.ids:
ids.append(r.id)
if ids:
return [('id', 'in', tuple(ids))]
return [('id', '=', '0')]
在导入导出大批量数据时,使用多线程模型,会明显加快速度,使用示例代码如下:
线程:
...
max_connections = 10
pool_sema = threading.BoundedSemaphore(max_connections)
for i in range(4):
pool_sema.acquire()
thread = threading.Thread(target=self.supplier_process, args=(arg1, arg2...))
thread.daemon = True
thread.start()
thread.join()
...
def supplier_process(self,args,**kwargs):
pass
线程池:
...
max_connections = 10
pool_sema = threading.BoundedSemaphore(max_connections)
with ThreadPoolExecutor(max_workers=5) as pool:
for i in range(4):
pool_sema.acquire()
thread = pool.submit(self.supplier_process, (pool_sema ,b), kwargs={'id': 1})
result = thread.result()
...
def supplier_process(self, *args, **kwargs):
...
pool_sema = arg[0][0]
...
pool_sema.release()
可以做一个订单的外部链接,示例代码如下:
...
order_link = fields.Html(string='订单链接')
...
@api.onchange('xxx)
def _compute_order_link(self):
self.ensure_one()
href = '/mail/view?model=%s&res_id=%s' %('sale.order', rec.order_id.id)
rec.order_link = '%s' %(href, rec.order_id.name)
odoo可以提供对外的接口,以实现与其它系统的互联互通,示例代码如下:
class Main(http.Controller):
@http.route('/xunde_bids/update/', type='json', methods=['POST'], auth="none",
csrf=False)
def update_bids(self, db=None, **post):
if not db and request.session.db and http.db_filter([request.session.db]):
db = request.session.db
if not db:
db = db_monodb(request.httprequest)
if not db:
raise exceptions.UserError(_('d参数不能为空'))
request.session.db = db
result = False
with registry(db).cursor() as cr:
env = Environment(cr, SUPERUSER_ID, {})
payload = json.loads(request.httprequest.data) or {}
type = payload.get('type', [])
if type:
raise exceptions.ValidationError(_('api失效!'))
data = payload.get('data', [])
result = env['purchase.requisition.line']._update_data(data)
return {'success': result} # result为True or False