Django ModelViewSet返回HTML错误页而非JSON响应,求解决方案
问题原因
当你调用Chat.objects.create()时,数据库因title唯一约束抛出IntegrityError,但Django REST Framework(DRF)默认不会自动捕获并转换这类数据库异常为JSON格式的字段级错误响应。若项目DEBUG=True,Django会直接返回默认的HTML错误回溯页面,而非符合API规范的JSON错误。
解决方案
方案1:序列化器提前校验title唯一性(推荐)
在序列化器中添加validate_title方法,在数据进入数据库前就检查title是否已存在,提前返回字段级错误,避免触发数据库异常:
class ChatSerializer(serializers.ModelSerializer): title = serializers.CharField(max_length=255) def validate_title(self, value): # 检查title是否已存在 if Chat.objects.filter(title=value).exists(): raise serializers.ValidationError("该聊天标题已存在,请更换其他标题") return value def create(self, validated_data): """ Creates a new Chat and adds the m2m employees to it """ user = self.context['request'].user title = validated_data['title'] # Add the user to the chat employee_ids = validated_data.pop("employee_ids") employee_ids.append(user.id) # Create and save the chat # Add the employees to the chat # Add the sender to the chat chat = Chat.objects.create(created_by=user, title=title) chat.employees.set(employee_ids) chat.employees.add(user) chat.save() return chat
方案2:捕获数据库异常转换为DRF验证错误
若不想提前校验,可在序列化器的create方法中捕获IntegrityError,抛出DRF的ValidationError,让框架返回JSON错误响应:
from django.db import IntegrityError from rest_framework import serializers class ChatSerializer(serializers.ModelSerializer): title = serializers.CharField(max_length=255) def create(self, validated_data): """ Creates a new Chat and adds the m2m employees to it """ user = self.context['request'].user title = validated_data['title'] # Add the user to the chat employee_ids = validated_data.pop("employee_ids") employee_ids.append(user.id) try: # Create and save the chat # Add the employees to the chat # Add the sender to the chat chat = Chat.objects.create(created_by=user, title=title) chat.employees.set(employee_ids) chat.employees.add(user) chat.save() return chat except IntegrityError as e: if "chats_chat_title_853c3234_uniq" in str(e): raise serializers.ValidationError({"title": "该聊天标题已存在,请更换其他标题"}) # 其他IntegrityError情况重新抛出 raise e
方案3:全局异常处理(多模型通用)
若项目中多个模型需处理同类唯一约束异常,可在DRF全局异常处理中添加对IntegrityError的处理:
在项目的views.py或专门的exceptions.py中定义:
from django.db import IntegrityError from rest_framework.views import exception_handler from rest_framework.response import Response from rest_framework import status def custom_exception_handler(exc, context): # 先调用DRF默认异常处理 response = exception_handler(exc, context) # 处理未被捕获的IntegrityError if response is None and isinstance(exc, IntegrityError): if "chats_chat_title_853c3234_uniq" in str(exc): return Response( {"title": ["该聊天标题已存在,请更换其他标题"]}, status=status.HTTP_400_BAD_REQUEST ) # 其他IntegrityError返回通用错误 return Response( {"detail": "数据库约束冲突"}, status=status.HTTP_400_BAD_REQUEST ) return response
然后在settings.py中配置:
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'your_project_name.views.custom_exception_handler', }
补充说明
- 方案1为最优解,提前在序列化器校验阶段处理,避免数据库操作,性能更优且符合DRF校验流程。
- 无论
DEBUG状态是True还是False,上述方案都能确保返回JSON格式的错误响应。
内容的提问来源于stack exchange,提问作者Nothing here
相关产品推荐
相关产品推荐

