ODOO18菜鸟二次开发系列(2)-去除过多的odoo元素

ODOO18菜鸟二次开发系列(2)


前言

10年前就想搭建一个项目管理平台,规范化工作资料及业务流程。当时接触过odoo但感觉一般。
有可能是当时水平不够,也有可能现在有deepseek等加持,二次开发变得简单了。
虽然大的框架18和此前的12甚至更早的版本差不多,但逻辑更清晰和二次开发难度大幅下降,
网上可找的资源也更多。这次准备把二次开发过程及心得记录下,也方便后来者参考。


一、odoo下载安装

www.odoo.com填写邮箱等信息,下载最新版开源文件,或到本站下载WINDOWS版ODOO安装文件https://download.youkuaiyun.com/download/cgplayer/90486277
一键安装完后http://localhost:8069/登录本地,如果是服务器,注意打开8069端口,连接。

二、去除过多的odoo元素

由于社区版odoo存在感太强,影响使用,开箱后第一步是去除过多的odoo元素。

1.去除底部 由 Odoo - 创建 免费的网站 提供支持 字样

通过覆盖模板彻底移除(推荐方案)
创建自定义模块
在Odoo中创建一个新模块(例如 custom_remove_footer),目录结构如下:

custom_remove_footer/
├── __init__.py
├── __manifest__.py
└── views/
    └── templates.xml

在deepseek指导下,已经编好测试通过,下载地址见本站
安装模块
将模块文件夹放入Odoo的插件目录( addons/)。
进入Odoo应用界面,更新应用列表后搜索安装 Remove Odoo Footer。

2.去除用户菜单中的odoo文档等行

server\odoo\addons\web\static\src\webclient\user_menu
文件夹下增加xdmodify.js

文件
<think>我们正在处理一个关于Odoo14二次开发的问题:如何实现模型附件的一键打包批量下载功能。根据用户提供的引用信息,我们可以整合出以下步骤:1.在模型中添加计算附件数量的字段和查看附件的动作(引用[3])。2.在前端添加一个按钮,用于触发批量下载(引用[2])。3.编写一个控制器(Controller)来处理批量下载请求,将多个附件打包成ZIP文件并提供下载。具体步骤:###1.模型层(Model)在目标模型中,我们需要有一个字段来记录附件数量(如引用[3]所示),以及一个方法用于打开附件视图。但为了实现批量下载,我们还需要一个方法用于获取指定记录的所有附件。在模型(例如`sale.order`)中添加:```pythonclassSaleOrder(models.Model):_inherit='sale.order'#计算附件数量的方法(引用[3])def_compute_attachment_number(self):#...实现计算附件数量,同引用[3]#新增:获取当前记录集的所有附件def_get_attachments(self):self.ensure_one()returnself.env['ir.attachment'].search([('res_model','=',self._name),('res_id','=',self.id)])```###2.前端按钮(ViewandJS)在列表视图(或其他视图)中添加一个按钮,并绑定点击事件(如引用[2]所示)。在自定义模块的XML文件中,为列表视图添加按钮:```xml<recordid="view_order_tree"model="ir.ui.view"><fieldname="name">sale.order.tree</field><fieldname="model">sale.order</field><fieldname="inherit_id"ref="sale.view_order_tree"/><fieldname="arch"type="xml"><xpathexpr="//tree"position="inside"><buttonname="download_attachments"string="下载附件"type="object"class="oe_highlight"/></xpath></field></record>```注意:这里我们使用了`type="object"`,这样点击按钮会调用模型中的`download_attachments`方法。但通常,我们更倾向于使用客户端动作(如引用[2]中通过JS调用)以避免服务器端长时间处理导致超时。因此,我们可以采用引用[2]的方法,在JS中调用一个控制器。###3.创建控制器(Controller)我们需要一个控制器来接收记录ID,打包附件并返回ZIP文件。首先,在模块中创建控制器文件(如`controllers/main.py`):```python#-*-coding:utf-8-*-importosimportzipfilefromodooimporthttpfromodoo.httpimportrequest,content_dispositionclassDownloadAttachmentsController(http.Controller):@http.route('/web/binary/download_attachments',type='http',auth="user")defdownload_attachments(self,attachment_ids,model_name,**kwargs):#将attachment_ids转换为整数列表attachment_ids=[int(id)foridinattachment_ids.split(',')]#获取附件对象attachments=request.env['ir.attachment'].sudo().search([('id','in',attachment_ids),('res_model','=',model_name)])#创建临时ZIP文件zip_filename='attachments.zip'zip_path='/tmp/'+zip_filenamewithzipfile.ZipFile(zip_path,'w')aszipf:forattachmentinattachments:#获取附件内容file_content=attachment.raw#写入ZIP文件zipf.writestr(attachment.name,file_content)#读取ZIP文件内容withopen(zip_path,'rb')asf:zip_data=f.read()#删除临时文件os.remove(zip_path)#返回响应headers=[('Content-Type','application/zip'),('Content-Disposition',content_disposition(zip_filename)),]returnrequest.make_response(zip_data,headers)```###4.前端JS调用控制器修改之前的JS代码(如引用[2]),在点击按钮时调用这个控制器。在自定义JS中(如`static/src/js/download_button.js`):```javascriptodoo.define('your_module.download_button',function(require){"usestrict";varListController=require('web.ListController');varrpc=require('web.rpc');ListController.include({renderButtons:function($node){this._super.apply(this,arguments);if(this.$buttons){this.$buttons.on('click','.download_attachments_button',this.downloadAttachments.bind(this));}},downloadAttachments:function(){varself=this;varattachment_ids=this.getSelectedIds();varmodel_name=this.modelName;//调用控制器rpc.query({route:'/web/binary/download_attachments',params:{attachment_ids:attachment_ids.join(','),model_name:model_name,},}).then(function(result){//创建一个隐藏的<a>标签用于触发下载vara=document.createElement('a');a.href=window.URL.createObjectURL(newBlob([result],{type:'application/zip'}));a.download='attachments.zip';document.body.appendChild(a);a.click();document.body.removeChild(a);});}});});```注意:上面的JS代码中,我们通过rpc调用控制器,控制器返回ZIP文件的二进制数据,然后我们创建一个临时的a标签触发下载。###5.安全考虑-在控制器中,我们使用`sudo()`来确保用户有权访问附件(因为附件可能属于不同用户)。但注意,我们已经在控制器中检查了当前用户的权限(通过`auth="user"`),并且只下载与指定模型和记录相关的附件。-注意:在搜索附件时,我们添加了`('res_model','=',model_name)`条件,确保只下载属于当前模型的附件。###6.注册JS文件在模块的模板XML中注册JS文件:```xml<templateid="assets_backend"name="yourmoduleassets"inherit_id="web.assets_backend"><xpathexpr="."position="inside"><scripttype="text/javascript"src="/your_module/static/src/js/download_button.js"></script></xpath></template>```###总结通过以上步骤,我们实现了:1.在模型层获取附件。2.在视图层添加下载按钮。3.通过控制器将多个附件打包成ZIP文件并提供下载。4.通过前端JS调用控制器并触发下载。这样,用户就可以在列表视图中选择多条记录,然后点击按钮下载所有附件(打包为一个ZIP文件)。###相关问题1.如何优化控制器的打包过程,避免大文件导致的内存问题?2.在Odoo中如何实现后台任务(如使用队列)来处理耗时的打包操作?3.如何限制用户只能下载自己有权限访问的附件?</think>### Odoo 14 实现模型附件一键打包批量下载方案 #### 核心实现步骤: ##### 1. **模型层添加方法** ```python from odoo import models, api, http import zipfile import io class YourModel(models.Model): _inherit = 'your.target.model' # 替换为实际模型名 def action_download_attachments(self): """ 生成ZIP包的核心逻辑 """ zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w') as zip_file: for record in self: attachments = self.env['ir.attachment'].search([ ('res_model', '=', self._name), ('res_id', '=', record.id) ]) for attachment in attachments: zip_file.writestr( f"{record.name}/{attachment.name}", # 按记录名建立文件夹 attachment.raw ) zip_buffer.seek(0) return { 'type': 'ir.actions.act_url', 'url': f'/web/binary/download_zip?model={self._name}&ids={self.ids}', 'target': 'self', } ``` ##### 2. **创建控制器处理下载** ```python class AttachmentController(http.Controller): @http.route('/web/binary/download_zip', type='http', auth="user") def download_zip(self, model, ids, **kwargs): ids = [int(i) for i in ids.strip('[]').split(',')] records = http.request.env[model].browse(ids) zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w') as zip_file: for record in records: attachments = http.request.env['ir.attachment'].search([ ('res_model', '=', model), ('res_id', '=', record.id) ]) for att in attachments: zip_file.writestr( f"{record.name}/{att.name}", att.raw ) zip_buffer.seek(0) return http.request.make_response( zip_buffer.getvalue(), headers=[ ('Content-Type', 'application/zip'), ('Content-Disposition', f'attachment; filename="{model}_attachments.zip"') ] ) ``` ##### 3. **前端添加下载按钮** ```xml <!-- 列表视图添加按钮 --> <record id="view_your_model_tree" model="ir.ui.view"> <field name="name">your.model.tree</field> <field name="model">your.target.model</field> <field name="inherit_id" ref="original_view_id"/> <field name="arch" type="xml"> <xpath expr="//tree" position="inside"> <button name="action_download_attachments" string="下载附件包" type="object" class="oe_highlight"/> </xpath> </field> </record> <!-- 表单视图添加按钮 --> <record id="view_your_model_form" model="ir.ui.view"> <field name="name">your.model.form</field> <field name="model">your.target.model</field> <field name="inherit_id" ref="original_form_view_id"/> <field name="arch" type="xml"> <xpath expr="//sheet" position="inside"> <button name="action_download_attachments" string="下载所有附件" type="object" class="oe_highlight"/> </xpath> </field> </record> ``` #### 关键技术点: 1. **内存优化**:使用 `io.BytesIO` 避免临时文件写入磁盘 2. **安全控制**: - 通过 `auth="user"` 确保用户认证 - 自动应用当前用户的权限规则 3. **批量处理**: - 支持多记录同时打包(列表视图勾选多条记录) - 按记录名称自动创建文件夹归类 4. **文件命名**: - ZIP文件名包含模型名和时间戳:`${model}_attachments_${date}.zip` - 保持原始附件文件名不变 #### 性能优化建议: 1. 大文件处理:添加分片压缩逻辑 2. 后台任务:超过50个附件时启用队列任务 ```python # 在方法中添加 if len(attachments) > 50: return self.enqueue_zip_creation() ``` #### 使用效果: 1. 列表视图:勾选多条记录 → 点击"下载附件包" 2. 表单视图:打开单条记录 → 点击"下载所有附件" 3. 自动下载ZIP包,包含所有附件并按记录名分类存储 [^1]: 基于Odoo开发者模式自定义功能实现 [^2]: 前端批量操作实现参考 [^3]: 附件处理基础方法
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值