【odoo18-文件管理】在uniapp上访问odoo系统上的图片

news/2025/2/25 16:53:25/

odoo_0">在uniapp上访问odoo系统上的图片

1、以url的形式访问
a:以odoo本身的域名,比如http://127.0.0.1:8069/web/image/product.template/3/image_128?unique=1740380422000,这种方式需要解决跨域的问题。
在这里插入图片描述

b:以文件服务器的形式,比如http://111.229.103.209/files/
在这里插入图片描述
2、odoo以Base64格式返回给uniapp,使用 Vue 的数据绑定来动态更新 src 属性。Base64 编码的图片会增大数据体积(大约增加 33%),对于大图片或大量图片,可能会影响性能和加载时间。

<template><view><image :src="dynamicBase64Image" style="width: 100px; height: 100px;"></image></view>
</template><script>
export default {data() {return {dynamicBase64Image: ''};},methods: {fetchBase64Image() {// 假设这里通过 API 获取 Base64 编码的图片uni.request({url: 'https://example.com/api/get-base64-image',success: (res) => {this.dynamicBase64Image = res.data.base64Image;}});}},onLoad() {this.fetchBase64Image();}
};
</script>

最终选择了以文件服务器的形式来访问。
服务器环境:腾讯云服务器ubuntu22.04

1.使用 Nginx 托管静态文件

1.1.nginx安装

sudo apt-get install nginx # 安装nginx
sudo service nginx restart # 重启nginx

1.2.nginx环境配置

cd /etc/nginx/ # 进入nginx目录,可以通过ls查看有哪些文件
cd sites-available # 进入sites-available
# 备份一个default
sudo cp default default.bak
sudo vim default

其中location /files就是文件共享目录

server {listen 80;server_name 111.229.103.209;  # 你的域名或服务器IP# 静态文件托管目录location /files {alias /etc/odoo/filestore;  # 你的文件存储路径autoindex on;          # 可选:开启目录浏览}location / {proxy_redirect     off;proxy_set_header   Host             $host;proxy_set_header   X-Real-IP        $remote_addr;proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;proxy_set_header   X-Forwarded-Proto $scheme;proxy_read_timeout 900;  # 根据需要调整超时时间proxy_connect_timeout 900;  # 根据需要调整超时时间proxy_pass         http://127.0.0.1:8069;  # Odoo的默认端口是8069}location /longpolling {proxy_redirect     off;proxy_set_header   Host             $host;proxy_set_header   X-Real-IP        $remote_addr;proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;proxy_set_header   X-Forwarded-Proto $scheme;proxy_read_timeout 36000s;  # 长轮询可能需要较长的超时时间proxy_pass         http://127.0.0.1:8072;  # Odoo的长轮询端口通常是8072}# 如果需要HTTPS,请添加SSL配置段(略)
}

1.3.文件效果

在这里插入图片描述
在这里插入图片描述

odoo_94">2.odoo对静态文件的读写

odooirattachment_95">2.1.odoo之ir.attachment

以产品图片为例:
在这里插入图片描述
odoo的ir.attachment有3层结构,这里的文件是图片。
1、文件本身对应了一个附件,用于存储文件本身,对于相同的文件,checksum和store_fname是相同的。
2、文件对应了一个webp附件,用于文件的附件地址。
3、产品图片,比如image_1920指向了文件的地址。对于image_1920、……、image_128,如果图片较小,odoo不会压缩图片,都会对应同一张图片;如果文件较大,odoo会根据尺寸限制压缩图片,不同尺寸的image会指向不同的图片地址。
在这里插入图片描述

2.2.静态文件的读写

# -*- coding: utf-8 -*-
import os
import base64
import binascii
import urllib.parse
from odoo import api, fields, models, _, _lt
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)class IrAttachment(models.AbstractModel):_inherit = 'ir.attachment'attachment_url = fields.Char('Attachment URL', help="The URL of the file in the remote server")def _is_image_mimetype(self):"""判断是否为图片类型"""return self.mimetype and (self.mimetype == 'image/jpeg' or self.mimetype == 'image/png')# return Truedef _sync_image_to_nginx(self, datas, filename):"""同步图片到Nginx目录"""nginx_dir = self.env['ir.config_parameter'].sudo().get_param('attachment.dir', '/etc/odoo/filestore')# 获取数据库名(替换非法字符)# nginx_dir = odoo.tools.config['data_dir']db_name = self.env.cr.dbname.replace('/', '_').replace('\\', '_')# 获取模型名(替换点号为下划线)nginx_dir += f'/{db_name}/files/'base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')url_parse = urllib.parse.urlparse(base_url)attachment_url = url_parse.scheme + '://' + url_parse.hostname + f'/{db_name}/files/'if not os.path.exists(nginx_dir):os.makedirs(nginx_dir, exist_ok=True)os.chmod(nginx_dir, 0o755)  # 确保目录权限file_path = os.path.join(nginx_dir, filename)try:with open(file_path, 'wb') as f:f.write(datas)_logger.info(f"图片已同步到Nginx目录: {file_path}")return attachment_urlexcept Exception as e:_logger.error(f"同步失败: {str(e)}")return False@api.model_create_multidef create(self, vals_list):res_ids = super().create(vals_list)for index in range(len(res_ids)):vals = vals_list[index]res_id = res_ids[index]description = vals.get('description', '')if not res_id.mimetype or not res_id.mimetype.startswith('image') or (description and description.startswith('resize')):continuestore_fname = res_id.store_fnameattachment_id = self.env['ir.attachment']if store_fname:attachment_id = self.env['ir.attachment'].search([('id', '!=', res_id.id),('res_model', '=', 'ir.attachment'),('store_fname', '=', store_fname),])if attachment_id and attachment_id.attachment_url:res_id.write({'attachment_url': attachment_id.attachment_url})continueif not res_id._is_image_mimetype():continueif not vals.get('res_id'):continueattachment_id = self.env['ir.attachment'].sudo().browse(vals.get('res_id'))datas = vals.get('datas')if not datas or not attachment_id:continue# Base64解码file_data = base64.b64decode(datas) or False# 同步到Nginxfilename = "%s_%s" % (store_fname.replace('/', '_').replace('\\', '_'), vals.get('name'))attachment_url = self._sync_image_to_nginx(file_data, filename)if attachment_url:attachment_id.write({'attachment_url': attachment_url})return res_idsdef unlink(self):"""删除时同步清理static文件"""for attach in self:if attach.attachment_url and os.path.exists(attach.attachment_url):try:os.remove(attach.attachment_url)# 尝试清理空目录dir_path = os.path.dirname(attach.attachment_url)if not os.listdir(dir_path):os.rmdir(dir_path)_logger.info(f"已删除: {attach.attachment_url}")except Exception as e:_logger.error(f"删除失败: {str(e)}")return super().unlink()def write(self, vals):try:bin_data = base64.b64decode(vals.get('datas', '')) or Falseexcept binascii.Error:raise UserError(_("Attachment is not encoded in base64."))if self.mimetype and self.mimetype.startswith('image'):checksum = self._compute_checksum(bin_data)attachment_id = self.env['ir.attachment'].search([('id', '!=', self.id),('res_model', '=', 'ir.attachment'),('checksum', '=', checksum),])if attachment_id and attachment_id.attachment_url:vals['attachment_url'] = attachment_id.attachment_urlreturn super(IrAttachment, self).write(vals)

在这里插入图片描述
在这里插入图片描述

2.3.静态文件的获取和显示

# -*- coding: utf-8 -*-
import json
import loggingfrom odoo.http import Controller, request, routeclass ProductController(Controller):@route(['/api/product/list'], type='http', auth='public', methods=['GET', 'OPTIONS'], csrf=False, cors='*')def api_product_list(self, **kw):logging.info('api_product_list:%s', kw)product_ids = request.env['product.product'].sudo().search([])data = []for product_id in product_ids:domain = [('res_model', '=', 'product.template'),('res_field', '=', 'image_1920'),('res_id', 'in', product_id.product_tmpl_id.id),]attachment_id = request.env['ir.attachment'].sudo().search(domain)data.append({'id': product_id.id,'name': product_id.name,'lst_price': product_id.lst_price,'thumbnail': attachment_id.attachment_url})return json.dumps({'code': 200, 'data': data, 'count': len(product_ids)})

在这里插入图片描述
在这里插入图片描述

3.总结

nginx静态文件的方式可以扩展到系统日志、备份等需要保存文件的场景。


http://www.ppmy.cn/news/1574870.html

相关文章

每日学习Java之一万个为什么

文章目录 16.前后端分离是怎么实现的&#xff1f;17.Servlet 和 Socket 区别18.为什么对于特别复杂的需求Servlet很难处理,怎么提前创建19.什么是JavaWeb中特别复杂的需求&#xff1f;20.为什么WebServlet可以代替配置文件&#xff1f;21.Tomcat 处理servlet流程22.web.xml的映…

计算机网络之路由协议(自治系统)

一、自治系统&#xff08;AS&#xff09; 自治系统是由同一个技术管理机构管理、使用统一选路策略的一些路由器的集合。它是网络的基本构成单位&#xff0c;每个自治系统是一个独立运营并自主决定与谁交换流量的实体。自治系统内部运行内部网关协议&#xff08;IGP&#xff09…

React Router v5 vs v6 路由配置对比

React Router v5 vs v6 路由配置对比 React Router 是 React 中最常用的路由库&#xff0c;从 v5 到 v6 版本&#xff0c;发生了较大变化。本文对比 React Router v5 和 React Router v6 的配置方式&#xff0c;帮助开发者顺利迁移。 1. 安装依赖 React Router v5 npm inst…

RFID涉密载体柜:智能安全,全程守护,提供智能化的安全管控

行业背景 RFID智能载体柜&#xff08;DW-G101&#xff09;是一种便捷化的载体管控系统&#xff0c;它采用RFID技术实现信息化&#xff0c;可以大大提高载体管理的效率和准确性。 随着信息化的快速发展&#xff0c;涉密载体&#xff08;如文件、U盘、光盘等&#xff09;的管理…

RabbitMQ的脑裂(网络分区)问题

问题描述&#xff1a; Mnesia reports that this RabbitMQ cluster has experienced a network partition. There is a risk of losing data 一、什么是MQ脑裂&#xff1f; 网络分区 如果另一个节点在一段时间内&#xff08;默认为 60 秒&#xff09;无法与其联系&#xff0…

MySQL缓存命中率

什么是缓存命中率 MySQL 缓存命中率是衡量 MySQL 查询性能的一个重要指标&#xff0c;它表示缓存中的数据被查询请求成功返回的比例。较高的缓存命中率通常意味着较少的磁盘 I/O 操作&#xff0c;查询响应速度较快。MySQL 中有多个类型的缓存&#xff0c;如 查询缓存、InnoD…

Golang连接使用SqlCipher

一、准备环境 需要下载MinGW、msys2、OpenSSL&#xff0c;并且注意都需要64位 已经整理成环境软件包&#xff0c;只需要下载&#xff0c;并配置环境变量 链接: https://pan.baidu.com/s/1NxF8aWqx7s97ntACOk77Ug 提取码: yhrv 二、代码 package mainimport ("database/s…

【大模型】AI 辅助编程操作实战使用详解

目录 一、前言 二、AI 编程介绍 2.1 AI 编程是什么 2.1.1 为什么需要AI辅助编程 2.2 AI 编程主要特点 2.3 AI编程底层核心技术 2.4 AI 编程核心应用场景 三、AI 代码辅助编程解决方案 3.1 AI 大模型平台 3.1.1 AI大模型平台代码生成优缺点 3.2 AI 编码插件 3.3 AI 编…