创建自定义响应消息时出现错误

14

我希望实现一个电子邮件验证系统,目前我已经想出了一个方法,虽然看起来有点“hacky”,但好像工作得很好。

我在函数的返回部分创建了一个自定义响应,但是我一直收到以下错误:

The response content must be rendered before it can be iterated over.

流程非常标准:有人注册,当我保存用户模型时,会有一个send_mail()函数,发送带有验证密钥的电子邮件。用户点击链接,并像这样传递密钥:

流程是标准的:有人注册,当我保存用户模型时,会调用send_mail()函数发送带有验证密钥的电子邮件。用户点击链接并通过以下方式传递密钥:

/api/account/verify/849c40665175e56709855cc7aec2b16c05a4d977b3b083790334c6bc01f6e522

在这个视图中,你可以看到我从中取出密钥并处理一切。我猜测错误是因为我在get_queryset()中使用了Response(),但我不确定。如果不是这样的话,那么我该如何创建自定义响应消息呢?

版本信息

Python==2.7.10
Django==1.11.4
djangorestframework==3.6.3

模型

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('email address'), null=False, unique=True)
    first_name = models.TextField(_('first name'), null=False)
    last_name = models.TextField(_('last name'), null=False)
    is_active = models.BooleanField(_('active'), default=False)
    is_admin = models.BooleanField(_('admin'), default=False)
    created_on = models.DateTimeField(_('create on'), auto_now_add=True)
    updated_on = models.DateTimeField(_('updated on'), auto_now=True)
    is_staff = models.BooleanField(_('staff'), default=False)
    activation_key = models.CharField(_('email validation key'), default='', max_length=256)

视图

class ActivateViewSet(generics.ListAPIView):

    queryset = User.objects
    serializer_class = ActivationSerializer

    def get_queryset(self):
        activation_key = self.kwargs['activation_key']
        if User.objects.all().filter(activation_key=activation_key).exists():
            User.objects.all().filter(activation_key=activation_key).update(is_active=True)
            return Response({'message': 'key accepted'}, status=status.HTTP_204_NO_CONTENT)
        raise NotFound('activation key not found')

序列化器

class ActivationSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email',)

跟踪回溯

File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  41.response = get_response(request)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.response = self.process_exception_by_middleware(e, request)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.return view_func(*args, **kwargs)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/django/views/generic/base.py" in view
  68.return self.dispatch(request, *args, **kwargs)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  489.response = self.handle_exception(exc)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/views.py" in handle_exception
  449.self.raise_uncaught_exception(exc)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
  486.response = handler(request, *args, **kwargs)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/generics.py" in get
  201.return self.list(request, *args, **kwargs)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/mixins.py" in list
  48.return Response(serializer.data)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  739.ret = super(ListSerializer, self).data
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/serializers.py" in data
  263.self._data = self.to_representation(self.instance)
File "/Users/*/.virtualenvs/video_env/lib/python2.7/site-packages/rest_framework/serializers.py" in to_representation
  657.self.child.to_representation(item) for item in iterable
File "/Users/*y/.virtualenvs/video_env/lib/python2.7/site-packages/django/template/response.py" in __iter__
  121.'The response content must be rendered before it can be iterated over.'

Exception Type: ContentNotRenderedError at /api/account/activate/849c40665175e56709855cc7aec2b16c05a4d977b3b083790334c6bc01f6e522/
Exception Value: The response content must be rendered before it can be iterated over.
1个回答

16

get_queryset 函数期望返回一个 queryset 对象而不是一个 Response 对象。您需要修改代码,使其返回一个类似于以下的对象:

def get_queryset(self):
        activation_key = self.kwargs['activation_key']
        if User.objects.all().filter(activation_key=activation_key).exists():
            users = User.objects.all().filter(activation_key=activation_key)
                                      .update(is_active=True)
            return user

现在,由于您要发送自定义响应,所以无法在 get_queryset 中完成。您需要覆盖序列化程序的 create 方法。下面是一个常规示例,说明如何覆盖此方法。

def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if not serializer.is_valid(raise_exception=False):
            return Response({"Fail": "blablal", status=status.HTTP_400_BAD_REQUEST)

        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response({"Success": "msb blablabla"}, status=status.HTTP_201_CREATED, headers=headers)

1
感谢您的反馈。我有点意识到使用 get_queryset() 尝试发送自定义响应是个问题。我有一个问题;因为我正在使用 GET,那么 create 仍然有效吗?我非常新手 Django,但我已经发现 Django 中有很多“魔法”发生。当我使用 create() 时,它会触发 GET 方法吗? - Mike
4
create方法适用于各种请求,因为它能创建响应你的请求所需的方法。 - Arpit Solanki
1
啊,不知道 :) - Mike
1
你好 @Mike,你能给我展示一下你是如何让它工作的吗? 提前感谢。 - MhmdRizk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接