DRF中使用.as_view({'post': 'list'})出现AttributeError问题求助
尝试向DRF端点发送文本(例如:"Hello World"),该端点需接收文本后发送包含此文本的邮件。使用Postman请求该端点时,触发以下错误:
Internal Server Error: /api/errors
Traceback (most recent call last):
File "/Users/sid/eb-virt/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/Users/sid/eb-virt/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/sid/eb-virt/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/sid/eb-virt/lib/python3.8/site-packages/rest_framework/viewsets.py", line 117, in view
handler = getattr(self, action)
AttributeError: 'ErrorMsgViewSet' object has no attribute 'list'
相关代码
urls.py
from django.urls import path from .api import * urlpatterns = [ path('api/errors', ErrorMsgViewSet.as_view({'post': 'list'}), name='errors'), ] # 我尝试过使用.as_view(),但报错要求改为上述格式 # 尝试使用router.register()结合generic.GenericAPIview时也出现错误
api.py
from rest_framework import viewsets from email_alerts.serializers import ErrorsSerializer class ErrorMsgViewSet(viewsets.GenericViewSet): serializer_class = ErrorsSerializer permission_classes = [ ] def post(self, request, *args, **kwargs): print(request.data)
models.py
from django.db import models # Create your models here. class ErrorsModel(models.Model): error_msg = models.CharField(max_length=5000, blank=True, null=True)
serializers.py
from rest_framework import serializers from email_alerts.models import ErrorsModel class ErrorsSerializer(serializers.ModelSerializer): error_msg = serializers.CharField( required=False, allow_null=True, allow_blank=True) class Meta: model = ErrorsModel fields = '__all__'
错误根源是URL配置与视图集方法的映射不匹配:
- 你在
urls.py中将POST请求映射到了list方法,但ErrorMsgViewSet并未定义该方法,反而自定义了post方法,二者完全不对应。 - DRF视图集的规范是用动作名称映射请求方法,比如
create对应POST请求,而非直接使用post方法名。
修改方案一(遵循视图集规范)
- 修改api.py:将自定义的
post方法重命名为create,并补充业务逻辑(保存数据、发送邮件):
from rest_framework import viewsets, status from rest_framework.response import Response from email_alerts.serializers import ErrorsSerializer from django.core.mail import send_mail class ErrorMsgViewSet(viewsets.GenericViewSet): serializer_class = ErrorsSerializer permission_classes = [] def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 可选:保存数据到数据库 serializer.save() # 发送邮件 error_msg = serializer.validated_data.get('error_msg') send_mail( '错误通知', error_msg, '你的发件邮箱@example.com', ['收件邮箱@example.com'], fail_silently=False, ) return Response(serializer.data, status=status.HTTP_201_CREATED)
- 修改urls.py:将POST请求正确映射到
create动作:
from django.urls import path from .api import ErrorMsgViewSet urlpatterns = [ path('api/errors', ErrorMsgViewSet.as_view({'post': 'create'}), name='errors'), ]
修改方案二(使用APIView简化)
如果不想遵循视图集动作规范,可直接改用APIView,支持直接定义post方法:
- 修改api.py:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from email_alerts.serializers import ErrorsSerializer from django.core.mail import send_mail class ErrorMsgAPIView(APIView): permission_classes = [] def post(self, request, *args, **kwargs): serializer = ErrorsSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 保存数据+发送邮件逻辑同上 error_msg = serializer.validated_data.get('error_msg') send_mail( '错误通知', error_msg, '你的发件邮箱@example.com', ['收件邮箱@example.com'], fail_silently=False, ) return Response(serializer.data, status=status.HTTP_201_CREATED)
- 修改urls.py:
from django.urls import path from .api import ErrorMsgAPIView urlpatterns = [ path('api/errors', ErrorMsgAPIView.as_view(), name='errors'), ]
完成修改后,用Postman发送POST请求到/api/errors,携带包含error_msg字段的JSON数据,即可正常触发邮件发送逻辑,不会再出现属性错误。
内容的提问来源于stack exchange,提问作者Sid

