淺談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一條記錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM