---
title: 2018-7-24 附件模块学习
tags: attachment
grammar_cjkRuby: true
---
1.安装附件模块(document,安装后会在form表单上方增加"attachment(s)"下拉选项)
主要是打开附件功能的界面以及上传文件的功能(该模块的model/ir_attachment.py)
实际附件核心在 odoo/addons/base/ir/ir_attachment.py
2.附件与模块无具体对应的关联表,附件统一保存在ir_attachment数据表里
3.附件的**定位方式**大概是 通过 res_model和res_id两个字段,定位到具体某模块的某条记录
4.如果字段加了attachment=True属性 那么该字段保存的文件(图片)也将当作 附件存储 ,我称为该附件为*字段附件*,通过点击attachment的add直接添加的附件为 *标准附件*。这两种附件的字段区分以 **res_field字段**是否为空为准,有field依赖则为字段附件(res_field在需要获取所有附件的情景有用处)
5.附件的**存储方式**是通过对附件数据生成一串唯一的hash值,然后用**store_fname字段**存储软地址的形式,告知odoo附件的存储位置,这样重复上传相同文件,此时系统不会再次重复上传,避免了不必要的开销,并增加一条对该附件的引用记录,删除操作则相反,当对该附件的引用记录为0时,系统将会删除该附件。
PS:在odoo的conf配置中,data_dir可以自定义数据存储路径(我在中途增加过该配置,但是重启后odoo的页面找不到css等路径,页面布局全乱了,目前未找到解决方案)
实例1:
1.说明:目前公司业务需要将前面的贷款业务(4个模型)中的所有附件保存到新模块(loan.record)中
2.达到的效果:降低前后模块的耦合,保证之前(4个模型)的记录删除后,新模块的附件不受影响
思路:(例子详情请见post_loan模块的inherit_apply.py)
1.生成一条(record模块)新记录
``` python
res = self.env['loan.record'].sudo().create(val)
if res:
self.get_relation_attachment_ids(res)
```
2.查询并获取所有模块中的所有附件(标准附件和字段附件)
``` python
def get_relation_attachment_ids(self,res):
...
# 根据res_model和res_id查询客户录入单附件
borrower_attachment = attachment_model.sudo().search([
('res_model', '=', self.borrower_id._name), ('res_id', '=', self.borrower_id.id),
'|', '|', ('res_field', '=', None), ('res_field', '=', 'frontimage'),
('res_field', '=', 'backimage')])
...
self.copy_attachment_data(res,borrower_attachment)
```
3.使用该新记录集的id(步骤1时生成的) 和模型名 生成一条 该记录 对 附件的引用(也就是增加一条附件引用记录,达到实例1的效果)
``` python
def copy_attachment_data(self,record,attachments):
# 循环附件的记录集(通常不止一个附件记录)
for attachment in attachments:
# 复制一份附件数据(返回list包dict的数据类型)
data = attachment.copy_data()[0]
# 根据模型名来给对应的附件改名
if data['res_model']=='loan.borrower':
if data['res_field']=='frontimage':
data['name'] =u'身份证正面(%s)' % attachment.res_name
...
# 最重要的是以下步骤
data['res_model'] = record._name
data['res_id'] = record.id
# 增加附件引用记录
self.env['ir.attachment'].sudo().create(data)
```
实例2:(附件预览)
直接点击
弹出新窗口查看该记录引用的附件
直接上代码:
函数
def attachment_image_preview(self):
self.ensure_one()
# domain可以过滤指定的附件类型 (mimetype)
domain = [('res_model','=',self._name),('res_id','=',self.id)]
return {
'domain': domain,
'res_model': 'ir.attachment',
'name': u'附件管理',
'type': 'ir.actions.act_window',
'view_id': False,
'view_mode': 'kanban,tree,form',
'view_type': 'form',
'limit': 20,
'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, self.id)
}
页面按钮
xml