- 路由
| @http.route('/web/binary/upload_attachment', type='http', auth="user") |
| @serialize_exception |
| def upload_attachment(self, callback, model, id, ufile): |
| files = request.httprequest.files.getlist('ufile') |
| Model = request.env['ir.attachment'] |
| out = """<script language="javascript" type="text/javascript"> |
| var win = window.top.window; |
| win.jQuery(win).trigger(%s, %s); |
| </script>""" |
| args = [] |
| for ufile in files: |
| |
| filename = ufile.filename |
| if request.httprequest.user_agent.browser == 'safari': |
| |
| |
| filename = unicodedata.normalize('NFD', ufile.filename) |
| |
| try: |
| attachment = Model.create({ |
| 'name': filename, |
| 'datas': base64.encodestring(ufile.read()), |
| 'datas_fname': filename, |
| 'res_model': model, |
| 'res_id': int(id) |
| }) |
| attachment._post_add_create() |
| except Exception: |
| args.append({'error': _("Something horrible happened")}) |
| _logger.exception("Fail to upload attachment %s" % ufile.filename) |
| else: |
| args.append({ |
| 'filename': filename, |
| 'mimetype': ufile.content_type, |
| 'id': attachment.id |
| }) |
| return out % (json.dumps(callback), json.dumps(args)) |
- 当文件内容保存在
datas
字段中时触发 inverse
方法:
| class IrAttachment(models.Model): |
| """Attachments are used to link binary files or url to any openerp document. |
| |
| External attachment storage |
| --------------------------- |
| |
| The computed field ``datas`` is implemented using ``_file_read``, |
| ``_file_write`` and ``_file_delete``, which can be overridden to implement |
| other storage engines. Such methods should check for other location pseudo |
| uri (example: hdfs://hadoopserver). |
| |
| The default implementation is the file:dirname location that stores files |
| on the local filesystem using name based on their sha1 hash |
| """ |
| _name = 'ir.attachment' |
| _description = 'Attachment' |
| _order = 'id desc' |
| |
| datas = fields.Binary(string='File Content', compute='_compute_datas', inverse='_inverse_datas') |
| |
| def _inverse_datas(self): |
| location = self._storage() |
| for attach in self: |
| |
| 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': |
| |
| vals['store_fname'] = self._file_write(value, vals['checksum']) |
| vals['db_datas'] = False |
| |
| |
| fname = attach.store_fname |
| |
| super(IrAttachment, attach.sudo()).write(vals) |
| if fname: |
| self._file_delete(fname) |
| |
| @api.model |
| def _file_write(self, value, checksum): |
| bin_value = base64.b64decode(value) |
| fname, full_path = self._get_path(bin_value, checksum) |
| if not os.path.exists(full_path): |
| try: |
| with open(full_path, 'wb') as fp: |
| fp.write(bin_value) |
| |
| self._mark_for_gc(fname) |
| except IOError: |
| _logger.info("_file_write writing %s", full_path, exc_info=True) |
| return fname |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
2021-09-27 网络 内网穿透frp