You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:01:29