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

I want to create an attachment from python code.

So, what I have tried:

    'store_fname' : ??,
    'checksum' : ??

What values should be passed for the column 'store_fname' and 'checksum' in ir_attachment table?


  • Those fields should be filled automatically:

    • The store_fnameis the folder and the name that the file uses when it is store in the filestore folder
    • The checksum concides with the file name as well. It is the result of applying the sha1 algorythm to the file data

    An example in the database:

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

    Take a look at how they are computed:

    @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)
                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:
    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',

    An example of how to create an attachment taken from BaseImportImport:

    def _create_csv_attachment(self, fields, data, options, file_name):
        # write csv
        f = StringIO()
        writer = csv.writer(f,
        encoding = options.get(OPT_ENCODING, 'utf-8')
        for row in data:
        # 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

    Though the fields res_id and res_model can be useful as well if you want to link the attachments to some record in some model

     id  |                 store_fname                 |                 checksum                 |    res_model     | res_id 
       1 | fc/fc78476ab1658bfedda7dde9b515d1c705472c1f | fc78476ab1658bfedda7dde9b515d1c705472c1f |      |      1
       2 | 97/97d5689a6bd71e33f9439f8235d54855a69134f3 | 97d5689a6bd71e33f9439f8235d54855a69134f3 |      |      2
     348 | 54/549f82ae56b7397db7fcd8ca1a179494b0cfda03 | 549f82ae56b7397db7fcd8ca1a179494b0cfda03 |       |     77
       3 | c5/c5fd52fe3cf431f70c6d778c555f027c97a0ac09 | c5fd52fe3cf431f70c6d778c555f027c97a0ac09 |      |      3