Django接口出现UnicodeDecodeError,如何返回图片URL?
问题与解决方案
问题说明
目标是在接口响应中返回图片URL,但直接返回request.data.get('img')触发UnicodeDecodeError,报错核心原因是无法解码图片的二进制字节(以0xff开头,属于图片文件原始二进制数据)。
为什么不能直接返回request.data.get('img')?
request.data.get('img')获取到的是二进制文件对象(InMemoryUploadedFile类型),并非字符串格式的URL。DRF在序列化响应内容时,会尝试将该二进制对象转换为UTF-8编码的字符串,而图片二进制数据不符合UTF-8编码规则,因此触发解码错误。
解决方案
要返回图片URL,需先将上传的图片保存到服务器指定位置,再生成对应的可访问URL返回。以下是两种可行实现方式:
方式一:使用Django模型存储图片(推荐)
- 定义模型存储图片字段:
# models.py from django.db import models class Image(models.Model): img = models.ImageField(upload_to='images/') # 图片将保存到MEDIA_ROOT/images/目录下
- 修改Serializer为ModelSerializer,新增URL生成逻辑:
# serializer.py from rest_framework import serializers from .models import Image class ImageSerializer(serializers.ModelSerializer): img_url = serializers.SerializerMethodField() def get_img_url(self, obj): # 生成图片的完整访问URL return self.context['request'].build_absolute_uri(obj.img.url) class Meta: model = Image fields = ['img', 'img_url']
- 修改视图逻辑,验证并保存图片后返回URL:
# views.py from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .serializer import ImageSerializer class ImageView(APIView): def post(self, request): serializer = ImageSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): serializer.save() return Response( {"processed_image_data": serializer.data['img_url']}, status=status.HTTP_200_OK ) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
方式二:手动保存图片(不依赖数据库模型)
若无需数据库存储,可手动将图片保存到服务器目录,再拼接URL返回:
# views.py import os from django.conf import settings from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .serializer import ImageSerializer class ImageView(APIView): def post(self, request): serializer = ImageSerializer(data=request.data) if serializer.is_valid(): img_file = request.FILES.get('img') if img_file: # 创建保存目录(不存在则自动生成) save_dir = os.path.join(settings.MEDIA_ROOT, 'images') os.makedirs(save_dir, exist_ok=True) # 写入图片文件 file_path = os.path.join(save_dir, img_file.name) with open(file_path, 'wb+') as f: for chunk in img_file.chunks(): f.write(chunk) # 生成可访问URL img_url = request.build_absolute_uri(f'/media/images/{img_file.name}') return Response( {"processed_image_data": img_url}, status=status.HTTP_200_OK ) return Response({"error": "未提供图片文件"}, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
必备配置
无论采用哪种方式,都需要在Django配置文件settings.py中添加媒体文件相关配置:
# settings.py MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'
同时在项目根路由urls.py中添加媒体文件访问路由:
# urls.py from django.conf import settings from django.conf.urls.static import static from django.urls import path urlpatterns = [ # 其他业务路由... ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
内容的提问来源于stack exchange,提问作者Mossaddak
相关产品推荐
相关产品推荐

