使用RetrieveUpdateDestroyAPIView时触发AttributeError问题求助
问题描述
我是Django新手,正在使用MongoEngine,通过DRF开发员工数据库。所有API运行正常,但尝试获取已删除的单条文档时,在employee/<int:pk>路径下触发AttributeError。
代码文件
models.py
from mongoengine import Document, SequenceField, StringField, IntField, EmailField from enum import Enum from rest_framework.exceptions import ValidationError class GenderEnums(str, Enum): MALE = "Male" FEMALE = "Female" OTHER = "Other" @classmethod def choices(cls): return [item.value for item in cls] class Employee(Document): employee_id = SequenceField(required=False, primary_key=True) name = StringField(required=True, max_length=50) age = IntField(required=True, min_value=18, max_value=50) company = StringField(required=True, max_length=50) gender = StringField(choices=GenderEnums.choices(), default=GenderEnums.OTHER) email = EmailField(required=True, unique=True) password = StringField(required=True) def clean(self): if self.gender == GenderEnums.MALE.value and self.age > 30: raise ValidationError("For male employees, age should be under 31") elif self.gender == GenderEnums.FEMALE.value and self.age < 20: raise ValidationError("For female employees, age should be above 20")
serializers.py
from rest_framework_mongoengine import serializers from .models import Employee class EmployeeSerializer(serializers.DocumentSerializer): class Meta: model = Employee fields = "__all__"
views.py
from .serializers import EmployeeSerializer from .models import Employee from rest_framework.response import Response from rest_framework_mongoengine import generics import logging from rest_framework.exceptions import ValidationError from mongoengine import DoesNotExist import time logging.basicConfig(filename="logs.txt", filemode="a", level=logging.INFO) class EmployeeAdd(generics.CreateAPIView): try: serializer_class = EmployeeSerializer logging.info(f"Document created successfully at {time.ctime()}") except ValidationError as e: Response(f"Validation error: {e}") except Exception as e: logging.error(f"Error occurred: {e}") Response(f"An error occurred while creating the document") class EmployeeAll(generics.ListAPIView): serializer_class = EmployeeSerializer queryset = Employee.objects.all() def get_queryset(self): queryset = self.queryset params = self.request.query_params if "name" in params: queryset = queryset.filter(name=params["name"]) if "age" in params: queryset = queryset.filter(age=params["age"]) return queryset class EmployeeOne(generics.RetrieveUpdateDestroyAPIView): serializer_class = EmployeeSerializer lookup_field = "pk" queryset = Employee.objects.all() def get_object(self): try: queryset = self.get_queryset() obj = queryset.get(pk=self.kwargs[self.lookup_field]) return obj except Exception as e: logging.error( f"Failed to retrieve document with the ID {self.kwargs[self.lookup_field]}" ) return Response( {"detail": "An error occurred while processing your request."}, status=500 ) def update(self, request, *args, **kwargs): try: response = super().update(request, *args, **kwargs) logging.info( f"Successfully updated document with ID {kwargs[self.lookup_field]}" ) return response except ValidationError as e: logging.error( f"Failed to update document with ID {kwargs[self.lookup_field]} due to validation error: {e}" ) return Response({"detail": e.detail}, status=e.status_code) except DoesNotExist: return Response({"detail": "Document not found."}, status=404) except Exception as e: logging.error( f"Failed to update document with ID {kwargs[self.lookup_field]} due to an error: {e}" ) return Response( {"detail": "An error occurred while processing your request."}, status=500 ) def destroy(self, request, *args, **kwargs): try: response = super().destroy(request, *args, **kwargs) logging.info( f"Successfully deleted document with ID {kwargs[self.lookup_field]}" ) return Response( f"Successfully deleted document with ID {kwargs[self.lookup_field]}" ) except DoesNotExist: return Response({"detail": "Document not found."}, status=404) except Exception as e: logging.error( f"Failed to delete document with ID {kwargs[self.lookup_field]} due to an error: {e}" ) return Response( {"detail": "An error occurred while processing your request."}, status=500 )
urls.py
from django.urls import path from .views import EmployeeAdd, EmployeeAll, EmployeeOne urlpatterns = [ path("register", EmployeeAdd.as_view()), path("employees", EmployeeAll.as_view()), path("employee/<int:pk>", EmployeeOne.as_view()), ]
触发的错误
AttributeError: "Got AttributeError when attempting to get a value for field `name` on serializer `EmployeeSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Response` instance. Original exception text was: 'Response' object has no attribute 'name'."
解决方案
问题核心在EmployeeOne类的get_object方法:DRF要求该方法必须返回模型实例,但你在查询失败时返回了Response对象,后续DRF会尝试用EmployeeSerializer序列化这个Response,自然找不到name字段,从而触发AttributeError。
修复get_object方法
不要返回Response,而是抛出DRF内置的NotFound异常,让框架自动处理成标准404响应:
from rest_framework.exceptions import NotFound def get_object(self): try: queryset = self.get_queryset() obj = queryset.get(pk=self.kwargs[self.lookup_field]) return obj except DoesNotExist as e: logging.error( f"Failed to retrieve document with the ID {self.kwargs[self.lookup_field]}: {e}" ) raise NotFound({"detail": "Document not found."}) except Exception as e: logging.error( f"Failed to retrieve document with the ID {self.kwargs[self.lookup_field]}: {e}" ) raise
修复EmployeeAdd类的异常处理
原代码把异常处理写在类定义顶层,不会生效(类初始化阶段还未处理请求),需要重写create方法:
class EmployeeAdd(generics.CreateAPIView): serializer_class = EmployeeSerializer def create(self, request, *args, **kwargs): try: response = super().create(request, *args, **kwargs) logging.info(f"Document created successfully at {time.ctime()}") return response except ValidationError as e: logging.error(f"Validation error: {e}") return Response(f"Validation error: {e}", status=400) except Exception as e: logging.error(f"Error occurred: {e}") return Response(f"An error occurred while creating the document", status=500)
修改后,请求已删除的文档会正确返回404响应,不会再触发AttributeError。
内容的提问来源于stack exchange,提问作者Kumar Sagar Maiti
相关产品推荐
相关产品推荐

