【问题标题】:DRF Use serializer to validate body and serialize responseDRF 使用序列化器验证正文并序列化响应
【发布时间】:2019-11-11 10:25:37
【问题描述】:

我在 django 中有以下视图,它登录用户并在使用序列化程序序列化用户数据后发回响应。

@api_view(['POST'])
def sign_in(request):
    username = request.data['username']
    password = request.data['password']
    user = authenticate(username=username, password=password)

    if user is not None:
        update_last_login(None, user)  # update the user's last login date
        serializer = UserSignInSerializer(user)
        return Response(serializer.data)

    return Response('Invalid login credentials', status=401)

我不喜欢这个视图的地方是我直接从正文中提取用户名和密码的方式。我想使用相同的序列化程序来检查正文是否有效。这是可能的还是我必须创建一个新的序列化程序来验证请求?这是现有的序列化程序:

class UserSignInSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'email', 'username', 'profile']

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    您可以使用 django rest 框架中的object level validation。这是一个不错的代码,您可以从django rest auth 使用。我在这里给你一个例子:

    class LoginSerializer(serializers.Serializer):
        username = serializers.CharField(required=False, allow_blank=True)
        password = serializers.CharField(style={'input_type': 'password'})
    
        def authenticate(self, **kwargs):
            return authenticate(self.context['request'], **kwargs)
    
        def _validate_username(self, username, password):
            user = None
    
            if username and password:
                user = self.authenticate(email=email, password=password)
            else:
                msg = _('Must include "username" and "password".')
                raise exceptions.ValidationError(msg)
    
            return user
    
        def validate(self, attrs):
            username = attrs.get('username')
            password = attrs.get('password')
            user = self._validate_username(username, password)
            if user:
                if not user.is_active:
                    msg = _('User account is disabled.')
                    raise exceptions.ValidationError(msg)
            else:
                msg = _('Unable to log in with provided credentials.')
                raise exceptions.ValidationError(msg)
    
            attrs['user'] = user
            return attrs
    

    并在视图中使用此序列化程序:

    @api_view(['POST'])
    def sign_in(request):
        serializer = LoginSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            user = serializer.validated_data['user']
            update_last_login(None, user)  # update the user's last login date
            u_serializer = UserSignInSerializer(user)
            return Response(u_serializer.data)
    
        return Response(serializer.errors, status=401)
    

    【讨论】:

    • 那么答案就是创建一个新的序列化程序?这是否意味着我必须为我拥有的每个视图创建两个序列化程序?一个用于req,一个用于res?
    • 您可以在一个序列化程序中制作它。但是,您需要使 first_name last name 等只读字段和密码只写字段。但是恕我直言,代码不会干净,一个序列化程序承担所有责任。但是拥有两个具有两个不同目的的序列化程序对我来说似乎更好。这样,您可以保持登录信息和用户信息不同,并更改其中任何一个,而不会影响其他
    • 另外,couldn't this mean that I would have to create two serializers for each view I have 是什么意思?
    • 您上面的视图使用了两个序列化器。如果请求正文包含与响应不同的数据,我可能不得不对我的所有视图执行此操作
    • 好吧,如果请求和响应完全不同,那么最好有两个序列化程序。但通常使用一个序列化程序。在这种情况下,正如我之前所说,您可以将它们合二为一。但为了更简洁的代码,我使用了两个序列化程序。
    猜你喜欢
    • 2017-11-09
    • 2020-08-14
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多