【问题标题】:Django Rest Framework number type still pass validation from modelDjango Rest Framework 数字类型仍然通过模型验证
【发布时间】:2019-12-19 06:46:51
【问题描述】:

您好,我目前正在尝试为我的更新 API 编写验证。我在我的序列化程序中使用了模型字段,因为我只希望在自定义用户模型中更新这些字段:

class UpdateUserSerializer(serializers.ModelSerializer):
   class Meta:
      model = User
      fields = (
        'email', 'uid', 'nickname', 'eth_address', 'eth_private_key', 'evt_address', 'evt_private_key'
        )

我的用户模型:

Class User(AbstractUser):

    uid = models.CharField(
        "uid", max_length=255, null=True, blank=True)
    phone_number = models.CharField(
        "Phone number", max_length=255, null=True, blank=True)
    nickname = models.CharField(
        "Nickname", max_length=255, null=True, blank=True)
    status = models.PositiveSmallIntegerField("Status", default=0)
    eth_address = models.CharField(
        "Eth address", max_length=255, null=True, blank=True)
    eth_private_key = models.CharField(
        "Eth private key", max_length=255, null=True, blank=True)
    evt_address = models.CharField(
        "Evt address", max_length=255, null=True, blank=True)
    evt_private_key = models.CharField(
        "Evt private key", max_length=255, null=True, blank=True)

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    # deleted

    class Meta:
        db_table = "users"

    pass

这是我的 DRF 更新模型视图:

class update_profile(RetrieveUpdateAPIView):
    permission_classes = ()
    authentication_classes = (FirebaseAuthentication,)

    def update(self, request):
        user_data = request.data
        user = User.objects.get(uid=request.user.uid)
        serializer = UpdateUserSerializer(user, data=user_data, partial=True)

        if user_data == {}:
            raise serializers.ValidationError({'code': 400, 'data': 'Invalid JSON object'})

        for key_name in user_data:
            if key_name not in ['email', 'uid', 'nickname', 'eth_address', 'eth_private_key', 'evt_address', 'evt_private_key']:
                raise serializers.ValidationError({'code': 400, 'data': 'Invalid input ' + key_name})

        if serializer.is_valid():
            updated_user = serializer.save()
            return JsonResponse({'code': 200,'data': updated_user.uid}, status=200)
        else:
            return JsonResponse({'code': 400,'errors':serializer.errors}, status=400)

我在 POSTMAN 上的输入如下:

{
    "email": "test@gmail.com",
    "uid": "dqwdqwd3123123",
    "nickname":"Alan",
    "eth_address": "dwdw",
    "eth_private_key": "fwef",
    "evt_address": "dwqdqwf",
    "evt_private_key": "dwqdqqd"
}

我想测试输入错误的条件,所以我输入了错误的电子邮件,例如wrongemail.com,并且验证正确:

{
    "code": 400,
    "errors": {
        "email": [
            "Enter a valid email address."
        ]
    }
}

但是当我尝试对"nickname": 4123414, 等其他类型进行错误输入时,即使在我设置nickname = models.CharField("Nickname", max_length=255, null=True, blank=True) 的模型中,它仍然可以通过验证,我不知道为什么数字的输入值通过了验证而没有引发错误。

【问题讨论】:

    标签: python django validation django-rest-framework


    【解决方案1】:

    首先,我认为您在这里所做的大部分工作,例如检查正确的字段,都是由序列化程序本身完成的。你只需要使用is_valid(raise=True),django 就会返回正确的 HTTP 响应(如果你使用默认的 django 错误处理程序 - 阅读更多in the docs

    你的视图应该是这样的:

    class update_profile(RetrieveUpdateAPIView):
        permission_classes = ()
        authentication_classes = (FirebaseAuthentication,)
    
        def update(self, request):
            user_data = request.data
            user = User.objects.get(uid=request.user.uid)
            serializer = UpdateUserSerializer(user, data=user_data, partial=True)
    
            if serializer.is_valid(raise_exception=True):
                updated_user = serializer.save()
                return JsonResponse({'code': 200,'data': updated_user.uid}, status=200)
    

    但是,我也认为 nick 示例实际上是正确的。数字可以转换为字符串,这就是序列化程序正在做的事情 -> 它将4123414 更改为'4123414'。如果您考虑一下,这是一个完全有效的昵称。您应该尝试其他示例,例如为 status 提供负数。

    【讨论】:

    • 那么有没有办法检查它是否真的是输入 json 中的字符串?因为有时前端会调用带有数字值的 api,并且他们希望它返回错误
    • 一个可靠的方法是编写自定义字段验证器,在此处阅读更多内容:django-rest-framework.org/api-guide/serializers/… 因此,如果不是is_instance(value, str),您将不得不做一些会引发验证错误的事情。应该很简单。不知道有什么更好的方法来做到这一点,但听起来这可能是一个流行的问题,所以我会在引入自定义方法之前进行一些谷歌搜索。
    • 这是一个类似的例子:stackoverflow.com/questions/31540221/…
    • 我决定在视图端编写验证,因为序列化程序中的所有内容都已转换为字符串,但感谢您的解释
    猜你喜欢
    • 2015-12-10
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2019-04-11
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 2015-12-26
    相关资源
    最近更新 更多