Django DRF笔记CRUD API更新接口request类型报错排查
问题描述
开发Django REST Framework笔记CRUD API时,笔记更新功能无法正常运行,访问更新接口路径/Note/update/4/时触发500内部服务错误。
相关代码
tools.py
from .models import Note from .serializers import NoteSerializer from rest_framework.response import Response from django.shortcuts import get_object_or_404 def getNoteslist(request): notes=Note.objects.all().order_by('-updated') serializer=NoteSerializer(notes, many=True) return Response(serializer.data) def NoteDetail(request, pk): notedetail=get_object_or_404(Note,id=pk) serializer=NoteSerializer(notedetail, many=False) return Response(serializer.data) def createNote(request): data=request.data note=Note.objects.create( title=data['title'], body=data['body'] ) serializer=NoteSerializer(note, many=False) return Response(serializer.data) def updateNote(request, pk): note=Note.objects.get(id=pk) serializer=NoteSerializer(instance=note, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) def delete(request, pk): note=get_object_or_404(Note,id=pk) note.delete() return Response('Note is deleted!')
views.py
from .models import Note from .tools import getNoteslist,NoteDetail,updateNote,createNote,delete from rest_framework.decorators import api_view @api_view(['GET']) def getNotes(request): return getNoteslist(request) @api_view(['POST']) def createNotes(request): return createNote(request) @api_view(['GET']) def getNote(request,pk): return NoteDetail(request, pk) @api_view(['POST']) def updateNote(request, pk): return updateNote(request, pk) @api_view(['DELETE']) def delNote(request, pk): return delete(request, pk)
urls.py
from django.urls import path from . import views from rest_framework.documentation import include_docs_urls from rest_framework_swagger.views import get_swagger_view schema_view=get_swagger_view(title='NOTE TAKING APi') API_TITLE='NOTE TAKING APi' API_DESCRIPTION='A note taking API for creating and editing notes.' urlpatterns=[ path('',views.getNotes,name='Notes'), path('create/',views.createNotes,name='Notes'), path('<int:pk>/',views.getNote,name='note'), path('update/<int:pk>/',views.updateNote,name='note'), path('delete/<int:pk>/',views.delNote,name='note'), path('docs/',include_docs_urls(title=API_TITLE, description=API_DESCRIPTION)), path('swagger-docs/',schema_view) ]
报错信息
Internal Server Error: /Note/update/4/ Traceback (most recent call last): File "C:\Users\Hp\anaconda3\lib\site-packages\django\core\handlers\exception.py", line 34, in inner response = get_response(request) File "C:\Users\Hp\anaconda3\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request) File "C:\Users\Hp\anaconda3\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\django\views\generic\base.py", line 71, in view return self.dispatch(request, *args, **kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\views.py", line 509, in dispatch response = self.handle_exception(exc) File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception raise exc File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\views.py", line 506, in dispatch response = handler(request, *args, **kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\decorators.py", line 50, in handler return func(*args, **kwargs) File "C:\Users\Hp\anaconda3\DJANGO\api\NoteTaking\Note\views.py", line 20, in updateNote return updateNote(request, pk) File "C:\Users\Hp\anaconda3\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\django\views\generic\base.py", line 71, in view return self.dispatch(request, *args, **kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\views.py", line 492, in dispatch request = self.initialize_request(request, *args, **kwargs) File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\views.py", line 391, in initialize_request return Request( File "C:\Users\Hp\anaconda3\lib\site-packages\rest_framework\request.py", line 154, in __init__ assert isinstance(request, HttpRequest), ( AssertionError: The `request` argument must be an instance of `django.http.HttpRequest`, not `rest_framework.request.Request`.
报错原因
核心问题是函数命名冲突导致递归调用:
- 你在
views.py中从tools模块导入了名为updateNote的工具函数,随后又在同文件定义了同名的视图函数updateNote,后者会覆盖前者的引用。 - 当请求命中视图函数时,函数内部执行
return updateNote(request, pk)时,调用的不是tools里的业务逻辑函数,而是被@api_view装饰的视图函数本身,形成递归调用。 - 第一次进入视图时,
@api_view装饰器已经把原生DjangoHttpRequest对象包装成了DRF的Request对象;递归调用时,这个DRF Request对象被再次传给被@api_view装饰的函数,而装饰器初始化逻辑要求传入的必须是原生HttpRequest对象,因此触发断言错误。
代码还存在3个潜在问题:
- 更新接口仅允许POST方法,不符合RESTful规范,更新操作应使用PUT/PATCH方法
- tools中更新逻辑直接用
Note.objects.get()查询对象,传入不存在的pk时会抛出DoesNotExist异常,没有做404处理 - 序列化器校验失败时没有返回错误信息,直接返回
serializer.data无法定位校验问题
修复方案
- 解决命名冲突:给导入的工具函数加别名,避免同名覆盖,同时修改视图允许的请求方法,调整
views.py对应代码:# 导入时给工具函数起别名 from .tools import getNoteslist,NoteDetail,updateNote as tool_updateNote,createNote,delete # 其余视图逻辑保持不变 @api_view(['PUT', 'PATCH']) # 允许更新场景常用的PUT、PATCH请求方法 def updateNote(request, pk): return tool_updateNote(request, pk) - 完善tools.py中的更新逻辑,补全404处理和校验错误返回:
def updateNote(request, pk): # 替换直接get查询,不存在的对应id直接返回404 note=get_object_or_404(Note,id=pk) serializer=NoteSerializer(instance=note, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) # 校验失败返回400状态码和具体错误信息 return Response(serializer.errors, status=400) - 接口测试时,使用PUT或PATCH方法请求
/Note/update/4/路径,传入需要更新的title、body字段参数即可正常完成更新操作。
内容的提问来源于stack exchange,提问作者Captain Leon
相关产品推荐
相关产品推荐

