zoukankan      html  css  js  c++  java
  • 浅谈odoo 后台与前端文件(附件)的存储与下载

    odoo 后台与前端文件(附件)存储与下载实现

     

    笔记太多了很乱,想想还是写博客的好,慢慢更

     

    当然了,前提是你已经配好了odoo开发环境

     


     

    一、odoo后台界面实现附件的上传和下载 

    1)、在应用中搜索下图组件,安装

    成功后,随便打开一个form视图就能看到上面多了一个附件按钮,点击即可上传

    2)、在你的模型中加入一个关联到这个附件模型的字段

    information_attachment = fields.Many2many('ir.attachment', compute='_get_attachment_ids', string=u'附件')

    这里使用的是Many2many进行关联

    ir.attachment 就是上图安装的模块Attachments……的模型的_name,这是odoo本身自带的附件模型功能,odoo后台上传的所有附件都会存到这个模型的数据库表里
    compute :根据所属的模型和实例获取附件

    既然如此,所有的附件都存在同一个模型中,如何知道那些附件是由哪个模型中的哪个实例上传的呢?

    我们先来看看数据库中ir.attachement的表

    字段太多了不一一解释

    res_model: 定义的模型名
    
    res_id:模型名实例化的对象id

    有个这两个字段,我们就能取到对应模型对面的特例(实例化对象)

    _get_attachment_ids方法就是用来获取附件

    1     def _get_attachment_ids(self):
    2         att_model = self.env['ir.attachment'] #获取附件模型
    3         for obj in self:
    4             query = [('res_model', '=', self._name), ('res_id', '=', obj.id)]   #根据res_model和res_id查询附件
    5             obj.information_attachment = att_model.search(query) #取得附件list

    根据上面代码取得附件,便可以显示出来了。

    3)、值得一提的是:

    <field name="information_attachment" widget="many2many_binary"/>

    在form视图xml文件中指定widget为 “many2many_binary”,则会如下图显示,更加直观

    点击相应的附件,即可下载。


    一点都不可爱的分割线 


     

    二、前端请求服务器,获取附件

    odoo后台实现了附件的上传和下载,那我的前端页面要怎么获取它呢?

    换句话说,我的controller要怎么写呢?

    1)、首先,前端取得你要获取附件的res_model和res_id,传回给后台附件id。

    根据前面的讲解,根据这两个字段可以取到一个附件list,要取得特定的附件,我还需要一个附件id

    attachment_id = request.env['ir.attachment'].sudo().search_read(
                [('res_model', '=', 'em.council.information'), ('res_id', '=', task_id)],
                ["name", "id"]

    这段代码,是在controller根据模型的res_model和res_id取得附件list,我存下了以下两个字段:

    name : 就是附件的名字  #用于前端的展示,给用户显示附件名称
    id:每个附件有一个特定的id #唯一标示,在数据库中查询附件用

    然后给前端返回去,至于怎么取到数据,就看你喜欢了,我用的是jinja2,ajax也可以

    如果是jinjia2,就返回

    return template.render(data=attachment_id)

    如果是ajax,自然就是

    Response(json.dumps(attachment_id), 200)

    然后你自己在前端中把他们渲染出来展示给用户

    2)、用户点击相应附件,实现下载

    用户点击了附件,我们有一个附件id,我们这里叫attachment_id,跟前面的attachment_id[1]存的id是一个东西

    1 function onReturnAttachment_id(attachment_id) {
    2     window.location.href = 'http://localhost:8069/w/download?attachment_id=' + attachment_id
    3 }

    为了方便讲解,前端偷懒直接用了跳转,请你不要偷懒,写一个阿贾克斯。

    上面的跳转已经暴露了我的路由是

    w/download

    然后传回了attachment_id给controller,接下来就是:

    1、controller取得attachment_id
    
    2、controller根据attachment_id查询数据库找到相应的附件
    
    3、controller给前端返回附件

    直接上代码:

     1 @http.route('/w/download', type='http', auth='public', csrf=False)
     2     def w_download_attachment(self, **kwargs):
     3         attachment_id = kwargs.get('attachment_id')
     4         attachment = request.env['ir.attachment'].sudo().search_read(
     5             [('id', '=', int(attachment_id))],
     6             ["name", "datas", "res_model", "res_id", "type", "url"]
     7         )
     8         if attachment:
     9             attachment = attachment[0]
    10         else:
    11             return redirect('/w/download')
    12 
    13         res_id = attachment['res_id']
    14         if attachment["type"] == "url":
    15             if attachment["url"]:
    16                 return redirect(attachment["url"])
    17             else:
    18                 return request.not_found()
    19         elif attachment["datas"]:
    20             data = StringIO(base64.standard_b64decode(attachment["datas"]))
    21             return http.send_file(data, filename=attachment['name'], as_attachment=True)
    22         else:
    23             return request.not_found()

    稍微解释一下:

    attachment_id = kwargs.get('attachment_id') #取得前端传回来的id
    #根据id取得数据库中对应的附件,其中datas就是我们的附件数据
    attachment = request.env['ir.attachment'].sudo().search_read(
                [('id', '=', int(attachment_id))],
                ["name", "datas", "res_model", "res_id", "type", "url"]
            )

    判断一下有没有取到,取到了又因为search_read返回一个list,但应该只有一条数据,因此 attachment = attachment[0]

            if attachment:
                attachment = attachment[0]
            else:
                return redirect('/w/download')

    1)、判断一下是不是存的url,是的话重定向

    2)、如果不是url存的,取得datas,base64解码一下存到data

    3)、把data和文件名打包返回给前端

     1         if attachment["type"] == "url":
     2             if attachment["url"]:
     3                 return redirect(attachment["url"])
     4             else:
     5                 return request.not_found()
     6         elif attachment["datas"]:
     7             data = StringIO(base64.standard_b64decode(attachment["datas"]))
     8             return http.send_file(data, filename=attachment['name'], as_attachment=True)
     9         else:
    10             return request.not_found()

    此时前端访问前面给的url便能下载对应附件了,比如我要下载前面存的附件中的“收藏的前端资料网址”,我理论上访问的是

    http://localhost:8069/w/download?attachment_id=266

    三、前端上传附件存到数据库中

    这个记录一下思路,其实就是一个逆过程,自己尝试一下

    1、拿到必要的字段,如res_model和res_id,你要存入附件的datas(base64编码格式)
    2、将数据传回controller
    3、controller处理数据,并操作数据库create一条记录
  • 相关阅读:
    魔数,常见魔数
    正则表达式 —— 括号与特殊字符
    串行总线 —— I2C、UART、SPI
    OpenCV-Python sift/surf特征匹配与显示
    OpenCV-Python 边缘检测
    python中zip()函数基本用法
    OpenCv-Python 图像滤波
    获取WMI硬件清单
    PowerShell查询sql server
    别名的应用(New-Alias)
  • 原文地址:https://www.cnblogs.com/ljwTiey/p/7348291.html
Copyright © 2011-2022 走看看