django restfremwork serializer的validate机制

       使用DRF去创建标准API的时候有一个日常操作就是serializer.is_valid(),用于检查序列化对象serializer是否合规,这个方法有一个参数叫raise_exception(boolean值),用于控制是不是抛出错误啥的。在自定义的serializer内自定义validate,方法名用validate和要做特殊检查的字段用下划线连起来命名就可以直接检查,比如要实现一个需求,邻居都不能姓王,那么就需要在自己对应的serializer内新增一个叫做validata_name的方法,可以这样写

class NeighbourSerializer(serializers.Serializer):
    """
    邻居们的序列化
    """

    ......
    ......
    name = serializers.CharField(max_length=100, allow_null=False)
    def validate_name(self, value):
        if value.first_name == '王':
            raise serializers.ValidationError(u'隔壁怎么可以姓王?')

        这个时候当代码运行起来会发现is_valid()时会自动进行检查,假如是我,我估计是拼接字符串,validate_当标志,后面拼上field名称当方法名然后调用。但是依然很好奇框架作者大神是如何实现的,所以看了看源码,整个调用流程是从is_valid()方法开始的,is_valid()内部会调用run_validation(data),然后run_validation()(注意,这个run_validation是Serializer类的,而不是Field的,rest_fremwork下自己封装的field也有一套名称一模一样的方法,跟踪的时候容易跟错),然后在run_validation内部会调用另外一个方法,叫做to_internal_value(data),这个方法是自定义validate的关键,源码如下:

def to_internal_value(self, data):
    """
    Dict of native values <- Dict of primitive datatypes.
    基本数据类型  ->  本地数据类型(我理解就是Serializer自己认的数据类型),顾注释思义!这玩意儿是用来使数据类型啥的变成合 乎自己逻辑的。
    """
    if not isinstance(data, Mapping):
        message = self.error_messages['invalid'].format(
            datatype=type(data).__name__
        )
        raise ValidationError({
            api_settings.NON_FIELD_ERRORS_KEY: [message]
        }, code='invalid')

    ret = OrderedDict()
    errors = OrderedDict()
    fields = self._writable_fields

    for field in fields:
        # 这里的fields内容就是我们在自定义的Serializer子类内标明的字段
        validate_method = getattr(self, 'validate_' + field.field_name, None)
        # 这一行果不其然用字符串拼接方法名的方式去获取对应的validate方法
        primitive_value = field.get_value(data)
        try:
            validated_value = field.run_validation(primitive_value)
            # 这一行就是上面说道的field也有一套validate的方法用于校验字段
            if validate_method is not None:
                validated_value = validate_method(validated_value)
                # 此处对自定义的validate方法进行了调用
        except ValidationError as exc:
            errors[field.field_name] = exc.detail
        except DjangoValidationError as exc:
            errors[field.field_name] = get_error_detail(exc)
        except SkipField:
            pass
        else:
            set_value(ret, field.source_attrs, validated_value)

    if errors:
        raise ValidationError(errors)

    return ret

结论:

1.自定义validate底层就是使用的字符串拼接,所以在使用这个机制的时候尽量复制粘贴field的名称避免单词拼写问题。

2.方法内读取的fields是直接self内去获取的Serializer自身定义过的field而不是Model内的,所以要使用这一机制,务必在自己的Serializer内创建对应的field.

### Django 身份验证机制详解 #### 1. 使用 JWT 进行身份验证 通过采用 JSON Web Token (JWT),可以在保证安全性的前提下显著减轻服务器端的管理负担,特别适合用于分布式系统中的身份认证需求[^1]。 为了在 Django 中集成 JWT 认证,需先安装 `djangorestframework` 和 `djangorestframework-simplejwt`: ```bash pip install djangorestframework pip install djangorestframework-simplejwt ``` 接着,在项目的设置文件 (`settings.py`) 中添加必要的配置项来启用 JWT 支持。这包括指定默认的身份验证类为 `TokenAuthentication`: ```python INSTALLED_APPS = [ ... 'rest_framework', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ), } ``` 对于 URL 配置部分,则需要将用户应用下的路由引入到主项目级别的 `urls.py` 文件中,并确保已导入 `include()` 函数以便于模块化处理不同子系统的路径映射关系[^2]: ```python from django.urls import path, include from django.contrib import admin urlpatterns = [ path('admin/', admin.site.urls), path('api/user/', include('users.urls')), ] ``` #### 2. 用户注册与登录接口设计 创建一个新的视图集以支持用户的注册和获取 token 的功能。这里可以利用 DRF 提供的基础 APIView 或者更高级别的 ViewSet 来快速构建所需的功能逻辑。下面是一个简单的例子展示如何定义这样的视图以及对应的序列化器: ```python # serializers.py from rest_framework import serializers from django.contrib.auth.models import User class RegisterSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('username', 'password') extra_kwargs = {'password': {'write_only': True}} def create(self, validated_data): user = User.objects.create_user(**validated_data) return user class LoginSerializer(serializers.Serializer): username = serializers.CharField() password = serializers.CharField(write_only=True) def validate(self, data): from django.contrib.auth import authenticate user = authenticate(username=data['username'], password=data['password']) if not user or not user.is_active: raise serializers.ValidationError("无法登录") return {"user": user} # views.py from rest_framework.views import APIView from rest_framework.response import Response from .serializers import RegisterSerializer, LoginSerializer from rest_framework_simplejwt.tokens import RefreshToken class RegisterAPIView(APIView): def post(self, request): serializer = RegisterSerializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.save() refresh = RefreshToken.for_user(user) response_data = { "refresh_token": str(refresh), "access_token": str(refresh.access_token), } return Response(response_data) class LoginAPIView(APIView): def post(self, request): serializer = LoginSerializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.validated_data.get('user') refresh = RefreshToken.for_user(user) response_data = { "refresh_token": str(refresh), "access_token": str(refresh.access_token), } return Response(response_data) ``` 最后一步是在 `urls.py` 中声明这些新创建的视图所对应的具体访问地址: ```python from django.urls import path from .views import RegisterAPIView, LoginAPIView app_name = 'users' urlpatterns = [ path('register/', RegisterAPIView.as_view(), name='register'), path('login/', LoginAPIView.as_view(), name='token_obtain_pair'), ] ``` 这样就完成了一个基本的支持 JWT 的用户注册及登录流程的设计与实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值