关于python的DRF框架中的数据校验方式

本文阐述了在DjangoRESTFramework中,如何通过序列化器进行数据验证,包括字段校验规则、is_valid()方法的应用以及在ModelSerializer中的集成,还涉及错误信息的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用DRF编写接口时,使用序列化器进行反序列化,校验数据大致分3步

  1. 在获取反序列化的数据前,必须调用is_valid() 方法进行验证,验证成功返回True,否则返回False。
  2. 验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
  3. 验证成功,可以通过序列化器对象的validated_data属性获取数据。

一、继承Serializer

继承Serializer(序列化器基类,drf中所有的序列化器类都必须继承于 Serializer),直接写在参数里和写在函数

1.校验规则直接写在参数中

from rest_framework import serializers

class demoSerializer(serializers.Serializer):
    amount = serializers.IntegerField(max_value=100, min_value=0, error_messages={
        "min_value": "The Age Filed Must Be 0 <= amount",  # amount在反序列化必须是 0 <= amount <= 100
        "max_value": "The amount Filed Must Be amount <= 100",
    })

返回给前端:

class DemoAPIView(APIView):
     def post(self, request, *args):
       try:
          serializer = demoSerializer(data=request.data)
          serializer.is_valid(raise_exception=True)
          # 拿出已验证的数据中的data
          validated_data = ser.validated_data.get('amount')
          #  返回信息
          return Response({"msg": "ok", "data":validated_data}, status=status.HTTP_201_CREATED)
       except ValidationError as e:
           return Response({"msg": "error", "error_message": e.detail}, status=status.HTTP_401_UNAUTHORIZED)

在DRF的序列化器中,raise_exception是一个可选参数,用于控制是否在验证失败时引发ValidationError异常。它的默认值是False,即当验证失败时,不会引发异常,而是将错误消息存储在序列化器的errors属性中。
这里的e.detail指的就是demoSerializer中amount的error_message。

2、写在函数里

继承Serializer,写在定义的validate函数中,一种是外部函数,一种是内部,其中写在内部的又分为两种,一种是校验多个字段,一种是校验单个字段

a.外部函数

写一个校验函数,在demoSerializer以外,可以导入的形式

from rest_framework import serializers

def check_num(data):
        """外部验证函数"""
         if len(data) != 3:
         raise serializers.ValidationError(detail="num格式不正        确!必须是3个字符", code="check_num")
       # 验证完成以后,务必返回结果,否则最终的验证结果没有该数据
         return data
      
class demoSerializer(serializers.Serializer):
   num = serializers.CharField(validators=[check_classmate])
     

返回给前端方式和上面一样

b.写在内部函数里

内部又分为两个,写在demoSerializer里面,一种适合验证多个的validate函数,一种是验证单个的validate_name函数

验证多个字段
class demoSerializer(serializers.Serializer):
   name = serializers.CharField(required=True)   # required=True , 反序列化阶段必填
    sex = serializers.BooleanField(default=True)  # default=True,  反序列化阶段,客户端没有提交,则默认为True
   
   def validate(self, attrs):
        """
        验证来自客户端的所有数据
        类似会员注册的密码和确认密码,就只能在validate方法中校验
        validate是固定方法名,
        参数:attrs,是在序列化器实例化时的data选项数据
        """
        if attrs.get("name") == "xxx" and attrs.get("sex"):
            raise serializers.ValidationError(detail="错误信息xx", code="validate")

        return attrs

    def validate_name(self, data):
        """验证单个字段
        方法名的格式必须以 validate_<字段名> 为名称,否则序列化器不识别!
        validate开头的方法,会自动被is_valid调用的
        """
        if data in ["python", "django"]:
            # 在序列化器中,验证失败可以通过抛出异常的方式来告知 is_valid
            raise serializers.ValidationError(detail="错误信息", code="validate_name")
        # 验证成功以后,必须返回数据,否则最终的验证结果中,就不会出现这个数据了。
        return data  

返回前端方式如上

验证单个字段
class demoSerializer(serializers.Serializer):
  name = serializers.CharField(required=True,
validators=[validate_name])   # required=True , 反序列化阶段必填
   def validate_name(self, data):
       """验证单个字段
       方法名的格式必须以 validate_<字段名> 为名称,否则序列化器不识别!
       validate开头的方法,会自动被is_valid调用的
       """
       if data in ["python", "django"]:
           # 在序列化器中,验证失败可以通过抛出异常的方式来告知 is_valid
           raise serializers.ValidationError(detail="错误信息", code="validate_name")
       # 验证成功以后,必须返回数据,否则最终的验证结果中,就不会出现这个数据了。
       return data  

二、继承的是ModelSerializer

models.py:

from django.db import models
# Create your models here.
class DemoModel(models.Model):
    """信息"""
    price = models.IntegerField(verbose_name="价格")
    class Meta:
        db_table = "mysql_demo"
        verbose_name = "demotest"
        verbose_name_plural = verbose_name

此时serializers.py应该是:


from rest_framework import serializers
from .models import DemoModel  #一定要导入models,py里写的model

class DemoModelSerializer(serializers.ModelSerializer):
    #...... 其他代码
    class Meta:
        model = DemoModel
        fields = "__all__"
        extra_kwargs = {
            "age": {
                "max_value": 100,
                "error_messages": {
                    "max_value": "价格不能超过100!",
                }
            }
        }

fields = ["字段1","字段2",....] 我这里的all指的是所有的字段。
views.py返回给前端的代码和上面相同

over

<think>好的,用户的问题是关于在DRF框架中使用djangorestframework-simplejwt对自定义用户模型进行token验证的实现方法。我需要结合提供的引用内容,整理出一个清晰的步骤指南。 首先,我需要确认用户已经完成了自定义用户模型的创建,并且在settings.py中正确设置了AUTH_USER_MODEL。根据引用1,用户需要将AUTH_USER_MODEL设置为'app_name.CustomUser',比如'user.SysUser'。这一步是关键,因为Django的认证系统依赖于这个设置来识别自定义用户模型。 接下来,用户需要安装并配置djangorestframework-simplejwt。引用2提到在REST_FRAMEWORK的DEFAULT_AUTHENTICATION_CLASSES中添加JWTAuthentication。这样DRF就会使用JWT进行认证。同时,用户可能还需要配置SIMPLE_JWT的一些参数,比如令牌有效期,但这些在引用中没有详细说明,可能需要查阅官方文档补充。 然后,处理用户登录接口。引用4指出需要修改登录接口的路径,将默认的TokenObtainPairView替换为自定义的视图类,比如LoginView。这里可能需要用户自己创建这个视图类,继承自TokenObtainPairView,并重写validate方法,以支持自定义用户模型的验证逻辑。引用3提到导入自定义的MyTokenObtainPairView并添加到路由中,这可能是用户需要实现的部分,确保登录时使用正确的用户模型进行认证。 另外,生成token的部分,引用3提到需要自定义token生成逻辑,可能需要创建自定义的序列化器或视图来返回包含额外信息的token。例如,在自定义的MyTokenObtainPairView中,重写get_token方法,添加自定义的claims。 最后,用户需要在接口中进行权限验证,使用@authentication_classes和@permission_classes装饰器,或者在settings中全局配置,确保请求需要有效的JWT token才能访问。 需要注意的坑可能有:确保所有引用正确导入,自定义用户模型的字段是否符合JWT的要求,比如是否有username字段,或者是否需要修改认证后端。同时,用户可能需要处理密码验证、用户状态检查(如是否激活)等问题,这些在自定义的validate方法中需要实现。 总结步骤应该是:设置AUTH_USER_MODEL → 配置DRF和simplejwt → 自定义登录视图 → 生成包含用户信息的token → 配置路由 → 验证接口权限。需要确保每一步都正确无误,并参考提供的引用内容中的代码示例。</think>在DRF框架中使用djangorestframework-simplejwt实现自定义用户模型的token验证,可通过以下步骤实现: ### 一、基础配置 1. **设置用户模型** 在settings.py中声明自定义用户模型路径: ```python AUTH_USER_MODEL = 'user.SysUser' # 格式为"应用名.模型类名"[^1] ``` 2. **配置DRF认证类** ```python REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_simplejwt.authentication.JWTAuthentication', ], # 其他配置... }[^2] ``` ### 二、登录接口改造 3. **创建自定义Token视图** 新建authentication.py文件,继承TokenObtainPairView: ```python from rest_framework_simplejwt.views import TokenObtainPairView from user.serializers import MyTokenObtainPairSerializer class MyTokenObtainPairView(TokenObtainPairView): serializer_class = MyTokenObtainPairSerializer ``` 4. **自定义Token生成逻辑** 在serializers.py中扩展Token声明: ```python class MyTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) token['user_id'] = user.user_id # 添加自定义字段 token['dept_code'] = user.department.code return token ``` ### 三、路由配置 5. **修改登录接口路由** ```python # urls.py from .authentication import MyTokenObtainPairView urlpatterns = [ path('login/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'), # 其他路由... ][^3][^4] ``` ### 四、接口验证 6. **添加权限验证装饰器** 在需要验证的视图类中添加: ```python from rest_framework.decorators import authentication_classes, permission_classes from rest_framework.permissions import IsAuthenticated @authentication_classes([JWTAuthentication]) @permission_classes([IsAuthenticated]) def protected_view(request): # 业务逻辑... ``` ### 需要注意的坑 - 确保自定义用户模型继承自`AbstractBaseUser`和`PermissionsMixin` - 若自定义了用户名字段(非username),需在序列化器中重写`username_field`配置 - JWT的payload默认有效期为5分钟,可在`settings.py`中通过`SIMPLE_JWT`配置项调整
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值