1
0
forked from erp-dev/erp
Files
erpnew/api_v1/views/product_image.py

186 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
产品图片上传视图
处理前后端分离场景下的图片上传
"""
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from basic_info.models import Product
import logging
logger = logging.getLogger(__name__)
class ProductImageUploadView(APIView):
"""
产品图片上传接口
支持两种方式:
1. 直接上传图片文件multipart/form-data
2. 更新已有产品的图片
"""
permission_classes = [IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
def post(self, request, product_id):
"""
上传/更新产品图片
请求参数:
- product_id: 产品 IDURL 路径参数)
- image: 图片文件multipart/form-data
前端使用示例:
```javascript
const formData = new FormData();
formData.append('image', file);
fetch('/api/v1/products/{id}/image/', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});
```
"""
# 检查用户权限
if not hasattr(request.user, 'employee'):
return Response(
{'error': '用户无员工信息,无权操作'},
status=status.HTTP_403_FORBIDDEN
)
merchant_id = request.user.employee.merchant_id
# 获取产品
try:
product = Product.objects.get(id=product_id, merchant_id=merchant_id)
except Product.DoesNotExist:
return Response(
{'error': f'产品 ID {product_id} 不存在或不属于当前商户'},
status=status.HTTP_404_NOT_FOUND
)
# 获取上传的图片
image_file = request.FILES.get('image')
if not image_file:
return Response(
{'error': '请提供图片文件字段名image'},
status=status.HTTP_400_BAD_REQUEST
)
# 验证文件类型
allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
if image_file.content_type not in allowed_types:
return Response(
{
'error': f'不支持的图片格式:{image_file.content_type}',
'allowed_types': allowed_types
},
status=status.HTTP_400_BAD_REQUEST
)
# 验证文件大小(最大 5MB
max_size = 5 * 1024 * 1024 # 5MB
if image_file.size > max_size:
return Response(
{
'error': f'图片大小超过限制:{image_file.size} bytes',
'max_size': f'{max_size / 1024 / 1024}MB'
},
status=status.HTTP_400_BAD_REQUEST
)
try:
# 保存图片(会自动上传到七牛云)
old_image = product.image
product.image = image_file
product.save(update_fields=['image', 'updated_at'])
# 删除旧图片(如果存在)
# 注意:七牛云的 delete 需要特殊处理,这里只是示例
if old_image:
try:
old_image.delete(save=False)
except Exception as e:
logger.warning(f"删除旧图片失败: {e}")
# 构建图片 URL
image_url = request.build_absolute_uri(product.image.url)
logger.info(
f"产品 {product_id} 图片上传成功,"
f"用户:{request.user.username},大小:{image_file.size} bytes"
)
return Response({
'message': '图片上传成功',
'product_id': product.id,
'image_url': image_url,
'image_name': product.image.name,
'size': image_file.size,
}, status=status.HTTP_200_OK)
except Exception as e:
logger.error(f"图片上传失败: {str(e)}", exc_info=True)
return Response(
{'error': '图片上传失败', 'message': str(e)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
def delete(self, request, product_id):
"""
删除产品图片
请求参数:
- product_id: 产品 IDURL 路径参数)
"""
# 检查用户权限
if not hasattr(request.user, 'employee'):
return Response(
{'error': '用户无员工信息,无权操作'},
status=status.HTTP_403_FORBIDDEN
)
merchant_id = request.user.employee.merchant_id
# 获取产品
try:
product = Product.objects.get(id=product_id, merchant_id=merchant_id)
except Product.DoesNotExist:
return Response(
{'error': f'产品 ID {product_id} 不存在或不属于当前商户'},
status=status.HTTP_404_NOT_FOUND
)
if not product.image:
return Response(
{'message': '产品没有图片'},
status=status.HTTP_200_OK
)
try:
# 删除图片
product.image.delete(save=False)
product.image = None
product.save(update_fields=['image', 'updated_at'])
logger.info(f"产品 {product_id} 图片已删除,用户:{request.user.username}")
return Response({
'message': '图片删除成功',
'product_id': product.id
}, status=status.HTTP_200_OK)
except Exception as e:
logger.error(f"图片删除失败: {str(e)}", exc_info=True)
return Response(
{'error': '图片删除失败', 'message': str(e)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)