如何在 Odoo 中创建新附件?它们是如何工作的?

How to create new attachments in Odoo? How do they work?

我想从 python 代码创建附件。

那么,我尝试过的是:

self.env['ir.attachment'].create({
    'store_fname' : ??,
    'checksum' : ??
})

ir_attachment table 中的 'store_fname' 和 'checksum' 列应传递什么值?

这些字段应该自动填写:

  • store_fname是文件存储在文件存储文件夹中时使用的文件夹和名称
  • checksum也与文件名一致。这是对文件数据应用sha1算法的结果

数据库中的示例:

 id  |                 store_fname                 |                 checksum                 
-----+---------------------------------------------+------------------------------------------
   1 | fc/fc78476ab1658bfedda7dde9b515d1c705472c1f | fc78476ab1658bfedda7dde9b515d1c705472c1f
   2 | 97/97d5689a6bd71e33f9439f8235d54855a69134f3 | 97d5689a6bd71e33f9439f8235d54855a69134f3
 348 | 54/549f82ae56b7397db7fcd8ca1a179494b0cfda03 | 549f82ae56b7397db7fcd8ca1a179494b0cfda03

看看它们是如何计算的:

@api.depends('store_fname', 'db_datas')
def _compute_datas(self):
    bin_size = self._context.get('bin_size')
    for attach in self:
        if attach.store_fname:
            attach.datas = self._file_read(attach.store_fname, bin_size)
        else:
            attach.datas = attach.db_datas

def _inverse_datas(self):
    location = self._storage()
    for attach in self:
        # compute the fields that depend on datas
        value = attach.datas
        bin_data = base64.b64decode(value) if value else b''
        vals = {
            'file_size': len(bin_data),
            'checksum': self._compute_checksum(bin_data),
            'index_content': self._index(bin_data, attach.datas_fname, attach.mimetype),
            'store_fname': False,
            'db_datas': value,
        }
        if value and location != 'db':
            # save it to the filestore
            vals['store_fname'] = self._file_write(value, vals['checksum'])
            vals['db_datas'] = False

        # take current location in filestore to possibly garbage-collect it
        fname = attach.store_fname
        # write as superuser, as user probably does not have write access
        super(IrAttachment, attach.sudo()).write(vals)
        if fname:
            self._file_delete(fname)

def _compute_checksum(self, bin_data):
    """ compute the checksum for the given datas
        :param bin_data : datas in its binary form
    """
    # an empty file has a checksum too (for caching)
    return hashlib.sha1(bin_data or b'').hexdigest()

# the field 'datas' is computed and may use the other fields below
datas = fields.Binary(
    string='File Content',
    compute='_compute_datas',
    inverse='_inverse_datas'
)

如何创建来自 BaseImportImport 的附件的示例:

@api.model
@api.returns('ir.attachment')
def _create_csv_attachment(self, fields, data, options, file_name):
    # write csv
    f = StringIO()
    writer = csv.writer(f,
                        delimiter=str(options.get(OPT_SEPARATOR)),
                        quotechar=str(options.get(OPT_QUOTING)))
    encoding = options.get(OPT_ENCODING, 'utf-8')
    writer.writerow(fields)
    for row in data:
        writer.writerow(row)
    # create attachment
    datas = base64.encodebytes(f.getvalue().encode(encoding))
    attachment = self.env['ir.attachment'].create({
        'name': file_name,
        'datas': datas,
        'datas_fname': file_name
    })
    return attachment

尽管字段 res_idres_model 也很有用,如果您想 link 某些模型中某些记录的附件

 id  |                 store_fname                 |                 checksum                 |    res_model     | res_id 
-----+---------------------------------------------+------------------------------------------+------------------+--------
   1 | fc/fc78476ab1658bfedda7dde9b515d1c705472c1f | fc78476ab1658bfedda7dde9b515d1c705472c1f | res.country      |      1
   2 | 97/97d5689a6bd71e33f9439f8235d54855a69134f3 | 97d5689a6bd71e33f9439f8235d54855a69134f3 | res.country      |      2
 348 | 54/549f82ae56b7397db7fcd8ca1a179494b0cfda03 | 549f82ae56b7397db7fcd8ca1a179494b0cfda03 | ir.ui.menu       |     77
   3 | c5/c5fd52fe3cf431f70c6d778c555f027c97a0ac09 | c5fd52fe3cf431f70c6d778c555f027c97a0ac09 | res.country      |      3