Django DRF调用serializer.is_valid()返回500内部服务器错误求助
问题原因及修复方案
核心问题1:序列化器传参错误
DRF的ModelSerializer初始化时,第一个位置参数默认是实例对象(用于序列化查询结果),如果是用于创建数据的反序列化场景,必须显式用data关键字参数传递请求数据;上传文件的场景还需要额外传递files参数对应request.FILES,原有写法会导致序列化器逻辑错乱抛出异常。
核心问题2:前端请求头配置错误
使用axios发送FormData格式请求时,禁止手动设置Content-Type: multipart/form-data。浏览器会自动生成该请求头,并且自动添加表单分隔用的boundary参数,手动设置会丢失boundary,导致Django无法正常解析上传的文件和表单数据。
可选配置检查
确认Django项目配置了媒体文件相关参数:
settings.py中添加以下配置:
import os MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'
- 项目根目录
urls.py中添加媒体文件访问路由(开发环境用):
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 原有路由配置 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
修复后的代码
前端color.js修改
删除手动设置的Content-Type请求头:
function PersonalColorScreen({navigation,route}) { const {image} = route.params; console.log('uri is', image.uri); const [userToken, setUserToken] = React.useState(route.params?.userToken); // 移除手动设置的Content-Type const requestHeaders = {} // helper function: generate a new file from base64 String //convert base64 image data to file object to pass it onto imagefield of serializer. //otherwise, serializer outputs 500 Internal server error code const dataURLtoFile = (dataurl, filename) => { const arr = dataurl.split(',') const mime = arr[0].match(/:(.*?);/)[1] const bstr = atob(arr[1]) let n = bstr.length const u8arr = new Uint8Array(n) while (n) { u8arr[n - 1] = bstr.charCodeAt(n - 1) n -= 1 // to make eslint happy } return new File([u8arr], filename, { type: mime }) } //random number between 0-9 function getRandomInt(max) { return Math.floor(Math.random() * max); } // generate file from base64 string const file = dataURLtoFile(image.uri, `${getRandomInt(10)}.png`) const formData= new FormData(); formData.append('img',file,file.name); console.log(file.name); //axios post request to send data axios.post('http://localhost:8000/accounts/personalcolor/', formData, requestHeaders) .then(res => { console.log(res); if (res.data === 'upload another image') { setimageError('upload another image'); } else { // signUp(userToken); let color; switch (res.data){ case ('spring'): color = 'spring'; break; case ('summer'): color = 'summer'; break; case ('fall'): color = 'fall'; break; case ('winter'): color = 'winter'; break; } } }) .catch(err => { console.error(err.response.data) })
后端view.py修改
修正序列化器传参,开启数据保存逻辑:
@api_view(['POST']) def personalcolor(request): # 显式传递data和files参数,修复缩进错误 serializer = ColorSerializer(data=request.data, files=request.FILES) # validation of input data,添加raise_exception=True避免未捕获异常抛出500 if serializer.is_valid(raise_exception=True): # 取消注释保存数据,才会将图片存入media目录 instance = serializer.save() # 可直接通过instance.img.url获取上传后的图片访问路径 return Response(serializer.data, status = status.HTTP_201_CREATED) else: return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
排查小技巧
如果修改后仍然报错,直接查看Django启动runserver的终端输出,500错误会打印完整的错误栈,可快速定位是权限问题、目录不存在问题还是其他配置问题。
内容的提问来源于stack exchange,提问作者Rebecca L
相关产品推荐
相关产品推荐

