使用图床服务存储图片的步骤如下:
-
选择图床服务提供商
常见的图床服务有 SM.MS、Imgbb、Postimage 等。选择时可以考虑服务稳定性、免费容量、上传速度等因素。 -
获取图床 API 密钥
大多数图床服务都提供 API 接口,需要先注册账号并获取相应的 API 密钥。这个密钥用于授权应用程序访问图床服务。 -
上传图片到图床
通常可以使用 HTTP POST 请求将图片数据上传到图床服务。可以把图片数据转换为 Base64 编码后上传,或者直接上传二进制数据。示例代码(使用 Python 和 requests 库):
import requests import base64 # 图片数据(Base64 编码) image_data = base64.b64encode(open('image.png', 'rb').read()) # 图床 API 密钥 api_key = 'your_api_key' # 请求头 headers = {'Authorization': api_key} # 上传文件 files = {'smfile': ('image.png', image_data)} url = 'https://sm.ms/api/v2/upload' response = requests.post(url, files=files, headers=headers) # 解析响应 data = response.json() if data['success']: image_url = data['data']['url'] print(f'Image uploaded successfully: {image_url}') else: print(f'Error uploading image: {data["message"]}')
-
将图片 URL 保存到数据库
在应用程序中,将上传成功后返回的图片 URL 保存到数据库中,以便后续使用。
使用图床服务可以避免将图片数据直接存储在数据库中,减轻数据库的负担。同时,图床服务通常提供更好的图片管理和访问功能。不过需要注意的是,需要考虑图床服务的可靠性和长期可用性。
def create(self, value_list): for value in value_list: value['image_id'] = self.env['ir.sequence'].next_by_code('image') # 图床 image_data = value['image'] image_data = base64.b64decode(image_data) headers = {'Authorization': '???'} files = {'smfile': ('image.png', image_data)} url = 'https://sm.ms/api/v2/upload' res = requests.post(url, files=files, headers=headers).json() value['image_path'] = res['data']['url'] print(res['data']['url']) print(value['image_path']) # 本地生成图片路径 # base_path = 'bitpulse/tutor/images' # image_data = value['image'] # timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S') # file_name = f'{timestamp}.png' # file_path = os.path.join(base_path, file_name) # # # 解码 Base64 编码的字符串为字节数据 # byte_data = base64.b64decode(image_data) # # byte_stream = io.BytesIO(byte_data) # 请求数据转化字节流 # # try: # roi_img = Image.open(byte_stream) # Image打开二进制流Byte字节流数据 # imgByteArr = io.BytesIO() # 创建一个空的Bytes对象 # roi_img.save(imgByteArr, format='PNG') # PNG就是图片格式 # imgByteArr = imgByteArr.getvalue() # 保存的二进制流 # # # 生成文件目录 # if not os.path.exists(base_path): # os.makedirs(base_path) # # # 创建图片 # with open(file_path, "wb+") as f: # f.write(imgByteArr) # # value['image_path'] = file_path # print(value['image_path']) # except IOError: # print("无法识别图像文件") return super().create(value_list)
这个 create
方法是用于创建多个图像记录的接口。下面是一些关键点:
- 遍历传入的
value_list
,对每个值进行处理。 - 为每个图像记录生成一个唯一的序列号,使用 Odoo 的
ir.sequence
模块。 - 从
value
字典中获取image
字段的 Base64 编码的图像数据。 - 使用
base64.b64decode()
函数将 Base64 编码的数据解码为原始的字节数据。 - 将图像数据上传到图床服务(sm.ms)。
- 使用
requests
库发送 POST 请求,上传图像并获取图像的 URL。 - 将图像 URL 存储在
image_path
字段中。
- 使用
- 这个接口还包含了注释掉的代码,用于在本地文件系统上存储图像。
- 根据当前时间戳生成文件名。
- 使用
Image
模块打开 Base64 编码的图像数据,并将其保存到本地文件系统。 - 将图像文件路径存储在
image_path
字段中。
- 如果出现
IOError
异常,则打印错误信息。 - 最后,调用父类的
create()
方法,将处理后的value_list
创建为新的记录。
这个接口的主要功能是:
- 为每个图像记录生成一个唯一的序列号。
- 将图像数据上传到图床服务,并将图像 URL 存储在数据库中。
- 作为一个批量创建图像记录的接口,调用父类的
create()
方法完成实际的数据库操作。
使用实例:
一个首页接口的实例
# 首页接口 @http.route(['/home'], type="json", auth="none", methods=['POST'], cors='*', csrf=False) def get_home(self, **kwargs): values = {'success': True, 'code': 200, 'message': '', 'data': ''} data = {'address': '', 'image': '', 'announcement': '', 'notice': '', 'academic_news': '', 'message': ''} address = [] title_address = request.env['tutor.title'].sudo().search([('name', '=', '上课区域')]) addresses = request.env['tutor.title.value'].sudo().search([('title_id', '=', title_address.id)]) for value in addresses: address.append(value.name) image_list = request.env['tutor.image'].sudo().search([], order='create_date desc') if len(image_list) < 5: image = [record.image_path for record in image_list] else: image = [record.image_path for record in image_list[:5]] print(image) print('****') announcement_list = request.env['tutor.announcement'].sudo().search([], order='create_date desc') if len(announcement_list) < 5: announcement = [value.content for value in announcement_list] else: announcement = [value.content for value in announcement_list[:5]] notice = [] notice_list = request.env['tutor.notice'].sudo().search([], order='create_date desc') for value in notice_list: notice_value = {'id': '', 'name': '', 'is_top': ''} notice_value['id'] = value.id notice_value['name'] = value.name notice_value['is_top'] = value.is_top notice.append(notice_value) academic_news = [] academic_list = request.env['tutor.academic.title'].sudo().search([]) for value in academic_list: academic_value = {'id': '', 'name': '', 'title': '', 'image': ''} academic_value['id'] = value.id academic_value['title'] = value.name academic_value['image'] = value.image academic_value['name'] = request.env['tutor.academic.kopp'].sudo().search([('titles', 'in', value.id)], limit=1).name academic_news.append(academic_value) message = [] message_list = request.env['tutor.message'].sudo().search([('invisible', '=', False), ('approve_message', '=', 'done')], order='create_date desc') if len(message_list) < 10: messages = [record for record in message_list] else: messages = [record for record in message_list[:5]] for value in messages: message_value = {'username': '', 'message': '', 'time': '', 'image': ''} customer = request.env['tutor.customer'].sudo().search([('id', '=', value.customer_id.id)]) message_value['username'] = customer.phone message_value['message'] = value.content message_value['image'] = value.customer_id.image message_value['time'] = value.time.strftime("%Y-%m-%d %H:%M:%S") message.append(message_value) data.update({'address': address, 'image': image, 'announcement': announcement, 'notice': notice, 'academic_news': academic_news, 'message': message}) values.update({'data': data}) return values # 滚轮 @http.route(['/rolling'], type="json", auth="none", methods=['POST'], cors='*', csrf=False) def rolling(self, **post): values = {'success': True, 'code': 200, 'message': '', 'data': ''} name = str(post.get('name')) page = int(post.get('page', 1)) per_page = 10 offset = (page - 1) * per_page data = [] if name == 'notice': notice_list = request.env['tutor.notice'].sudo().search([], order='create_date desc') page_notice = notice_list[offset:offset + per_page] data = [{'id': value.id, 'name': value.name, 'is_top': value.is_top} for value in page_notice] else: message_list = request.env['tutor.message'].sudo().search([('invisible', '=', False), ], order='create_date desc') page_notice = message_list[offset:offset + per_page] for value in page_notice: customer = request.env['tutor.customer'].sudo().search([('id', '=', value.customer_id.id)]) data.append({'username': customer.phone, 'time': value.time.strftime("%Y-%m-%d %H:%M:%S"), 'message': value.content, 'image': value.customer_id.image}) values['data'] = data return values
这个 Python 代码实现了两个 Odoo 的 HTTP 路由接口,用于获取首页和滚动列表的数据。
-
Odoo 路由机制
- Odoo 使用
http.route()
装饰器定义 HTTP 路由,可以指定 URL 路径、请求方法、认证方式等。 type="json"
表示该路由返回 JSON 格式的数据。auth="none"
表示该路由不需要用户认证。cors='*'
表示支持跨源资源共享。csrf=False
表示不进行 CSRF 验证。
- Odoo 使用
-
数据查询
- 使用
request.env['model_name'].sudo().search()
查询 Odoo 模型中的数据。 sudo()
方法使用管理员权限查询数据。- 可以通过条件过滤、排序等参数优化查询结果。
- 使用
-
数据组织和返回
- 将查询到的数据整理成所需的数据结构,如字典或列表。
- 将整理好的数据更新到
values
字典中,作为最终返回的 JSON 数据。
-
分页处理
- 在
/rolling
接口中,使用page
和per_page
参数实现了分页功能。 - 通过计算
offset
来获取当前页的数据。
- 在
-
查询优化
- 在首页接口中,根据数据长度进行了截取,以限制返回数据的数量。
- 在滚动列表接口中,也仅返回当前页的数据,减轻了服务器负担。
总的来说,这个代码展示了 Odoo 中使用 HTTP 路由、数据查询、数据组织和返回,以及分页处理的基本知识。