DRF 03

序列化家族

  • 序列化就是==將對象的狀態信息轉換爲能夠存儲或傳輸的形式的過程==
"""
一、Serializer類:底層序列化類 - 瞭解類
    重點:單表序列化

二、ModelSerializer類:模型序列化類 - 核心類
    重點:多表序列化
    
三、ListSerializer類:羣操做序列化類 - 輔助類
    重點:輔助完成單表多表羣增羣改操做
"""

手動實現序列化

  • 這裏的手動實現指的是將對象信息傳輸到前端
# 1.自定義序列化版本
class UserV1APIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        print(pk)
        # 單查
        if pk:
            user_dic = models.User.objects.filter(is_delete=False, pk=pk).values('username', 'gender', 'avatar').first()

            # 查詢不到時
            if not user_dic:
                return Response(
                    {'status': 1, 'msg': 'id error'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 對頭像路徑進行拼接
            user_dic['avatar'] = f"{settings.BASE_URL}{settings.MEDIA_URL}{user_dic.get('avatar')}"

            return Response({
                'status': 0,
                'msg': 'ok',
                'results': user_dic
            })

        # 羣查
        else:
            user_query = models.User.objects.filter(is_delete=False).values('username', 'gender', 'avatar')
            for user_dict in user_query:
                # 對頭像路徑進行拼接
                user_dict['avatar'] = f"{settings.BASE_URL}{settings.MEDIA_URL}{user_dict.get('avatar')}"
            user_list = list(user_query)
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': user_list
            })

Serializers序列化與反序列化

序列化

  • 字段設置: 要同模型類的字段對應
  • 自定義序列化字段:
    • 字段類型爲: SerializerMethodField()
    • 字段名不該和模型類字段名衝突
    • 經過定義 get_自定義字段名(self, obj) 方法來獲取要序列化的值
"""
1.新建一個serializers.py文件
2.導入: from rest_framework import serializers
3.新建一個類, 繼承serializers.Serializer
4.在類中添加須要序列化的字段, 字段名要與模型類中的字段相對應
5.自定義的字段不該該和模型類字段重名, 經過定義 'get_字段名' 方法來獲取要序列化的值
"""

# serializers.py中定義
class UserSerializer(serializers.Serializer):
    # 字段名要與模型類中的字段相對應
    username = serializers.CharField()

    # 自定義序列化字段須要兩個參數: self和obj(模型類對象)
    # 自定義序列化字段不該與模型類字段重合, 經過'get_自定義字段名'方法獲取值進行序列化
    user_gender = serializers.SerializerMethodField()

    def get_user_gender(self, obj):
        return obj.get_gender_display()

    user_avatar = serializers.SerializerMethodField()

    def get_user_avatar(self, obj):
        return f"{settings.BASE_URL}{settings.MEDIA_URL}{obj.avatar}"
    
    
----------------------------------------------------------------------------------------------------


"""
視圖類序列化過程
1)ORM操做獲得數據
2)將數據序列化成能夠返回給前臺的數據
3)返回數據給前臺
"""    

# views.py中使用
class UserV2APIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')

        # 單查
        if pk:
            user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()

            # 查詢不到時
            if not user_obj:
                return Response(
                    {'status': 1, 'msg': 'id error'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 傳入數據對象, 生成序列化對象
            serializer_obj = serializers.UserSerializer(user_obj, many=False)

            return Response({
                'status': 0,
                'msg': 'ok',
                # 序列化後數據存放在序列化對象的data屬性中
                'results': serializer_obj.data
            })

        # 羣查
        user_query = models.User.objects.filter(is_delete=False).all()
        # 當序列化多個數據對象時, 要設置 many=True
        serializer_obj = serializers.UserSerializer(user_query, many=True)

        return Response({
                'status': 0,
                'msg': 'ok',
            # 序列化後數據存放在序列化對象的data屬性中
                'results': serializer_obj.data
            })

反序列化

  • 自定義字段和普通字段的設置內有區別
  • 自定義字段不能直接入庫, 須要設置入庫規則, 或在鉤子中將其移除
  • 局部鉤子:
    • validate_字段名(self, value) value是字段的值
    • 經過校驗返回value, 不然拋出錯誤信息: raise serializers.ValidationError({'字段名': '錯誤信息'})
  • 全局鉤子:
    • validate(self, attrs) attrs是包含字段(鍵)和字段值(值)的字典
    • 經過校驗返回attrs, 不然拋出錯誤信息: raise serializers.ValidationError({'字段名': '錯誤信息'})
  • 重寫create方法實現增入庫,返回入庫成功的對象
  • 重寫update方法實現改入庫,返回入庫成功的對象
# Serializer反序列化
class UserDeSerializer(serializers.Serializer):
    username = serializers.CharField(min_length=3, max_length=12, error_messages={
        'min_length': '不能少於三個字符',
        'max_length': '不能長於12個字符',
    })

    password = serializers.CharField(min_length=3, error_messages={
        'min_length': '不能少於三個字符',
    })

    # 只要有該字段, 則就必須參與反序列化, 能夠經過required=False設置不參與
    gender = serializers.BooleanField(required=False)

    # 自定義校驗字段, 不參於入庫操做, 須要在全局鉤子中取出
    re_password = serializers.CharField(min_length=3, error_messages={
        'min_length': '不能少於三個字符',
    })

    # 局部鉤子
    def validate_username(self, value):
        if value.lower() == 'bigb':
            raise serializers.ValidationError('不能和我同名!')
        return value

    # 全局鉤子
    def validate(self, attrs):
        password = attrs.get('password')
        re_password = attrs.pop('re_password')
        if not password == re_password:
            raise serializers.ValidationError({'re_password': '密碼輸入不一致'})

        return attrs

    # 增長操做
    def create(self, validated_data):
        return models.User.objects.create(**validated_data)

    # 修改操做
    def update(self, instance, validated_data):
        # 用戶名不能被修改
        validated_data.pop('username')
        models.User.objects.filter(pk=instance.id).update(**validated_data)
        return instance
    
    
    
----------------------------------------------------------------------------------------------------

"""
# 視圖類反序列化過程
# 1)從請求對象中獲取前臺提交的數據
# 2)交給序列化類完成反序列化(數據的校驗)
# 3)藉助序列化類完成數據入庫
# 4)反饋給前臺處理結果
"""

# 單增
def post(self, request, *args, **kwargs):
    request_data = request.data
    print(request_data)
    serializer_obj = serializers.UserDeSerializer(data=request_data)
    if serializer_obj.is_valid():
        # 經過save()方法進行入庫
        user_obj = serializer_obj.save()

        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializers.UserSerializer(user_obj).data
        })

    else:
        return Response({
            'status': 1,
            'msg': serializer_obj.errors
        })

ModelSerializer序列化與反序列化

  • 繼承了ModelSerialzer類, 須要在配置類Meta中進行配置
    • model: 綁定模型類
    • field: 設置全部參與序列化與反序列化的字段
    • extra_kwargs:
      • 劃分系統字段爲三種: read_only, write_only, 不設置(可讀可寫)
      • 字段限制條件
  • 自定義序列化字段
    • 在序列化類中用SerializerMethodField()來實現
    • 在模型類中用@property自定義方法屬性來實現 (可插拔)
  • 自定義反序列化字段:
    • 同Serializer類, 且限制條件只能在此聲明, 或者在鉤子中進行判斷, 不能在extra_kwargs進行設置
  • 局部鉤子和全局鉤子同Serializer類同樣
  • 不須要從新create和update方法
# ModerSerializer序列化與反序列化
class UserModelSerializer(serializers.ModelSerializer):
    # 第一種自定義序列化字段方法, 必須在fields中設置
    # user_gender = serializers.SerializerMethodField()
    #
    # def get_user_gender(self, obj):
    #     return obj.get_gender_display()

    # 自定義反序列化字段同Serializer中一致, 且校驗規則只能一併聲明, 或者在鉤子判斷, 在extra_kwargs設置無效
    re_password = serializers.CharField(min_length=3,
                                        error_messages={'min_length': '不能少於三個字符'},
                                        write_only=True)

    class Meta:
        # 綁定模型表
        model = models.User
        # 設置全部參與序列化與反序列化的字段(插拔式設計)
        fields = ('username', 'password', 'user_gender', 'gender', 'user_avatar', 're_password')
        extra_kwargs = {
            # 不設置write_only和read_only表名該字段可讀可寫
            'username': {
                'min_length': 3,
                'max_length': 12,
                'error_messages': {
                    'min_length': '不能少於3個字符',
                    'max_length': '不能長於12個字符',
                }
            },
            'password': {
                'write_only': True
            },
            'user_gender': {
                # 自定義的序列化字段默認就是read_only, 且不能修改
                'read_only': True
            },
            'gender': {
                'write_only': True,
                'required': False,
            }
        }

    # 局部鉤子與Serializer一致
    def validate_username(self, value):
        if value.lower() == 'bigb':
            raise serializers.ValidationError('不能和我同名!')
        return value

    # 全局鉤子與Serializer一致
    def validate(self, attrs):
        password = attrs.get('password')
        re_password = attrs.pop('re_password')
        if not password == re_password:
            raise serializers.ValidationError({'re_password': '密碼輸入不一致'})
        return attrs
    
    
----------------------------------------------------------------------------------------------------
    
    
# ModelSerializer序列化與反序列化
class UserV3APIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')

        # 單查
        if pk:
            user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()

            # 查詢不到時
            if not user_obj:
                return Response(
                    {'status': 1, 'msg': 'id error'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 傳入數據對象, 生成序列化對象
            serializer_obj = serializers.UserModelSerializer(user_obj, many=False)

            return Response({
                'status': 0,
                'msg': 'ok',
                # 序列化後數據存放在序列化對象的data屬性中
                'results': serializer_obj.data
            })

        # 羣查
        user_query = models.User.objects.filter(is_delete=False).all()
        # 當序列化多個數據對象時, 要設置 many=True
        serializer_obj = serializers.UserModelSerializer(user_query, many=True)

        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializer_obj.data
        })

    # 單增
    def post(self, request, *args, **kwargs):
        request_data = request.data
        print(request_data)
        serializer_obj = serializers.UserModelSerializer(data=request_data)
        if serializer_obj.is_valid():
            # 經過save()方法進行入庫
            user_obj = serializer_obj.save()

            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.UserSerializer(user_obj).data
            })

        else:
            return Response({
                'status': 1,
                'msg': serializer_obj.errors
            })
相關文章
相關標籤/搜索