Django REST framework之序列化

1. 序列化基本使用

数据准备:

models.py:

from django.db import models


class UserInfo(models.Model):
    user_type_choices = (
        (1, '普通用户'),
        (2, 'VIP用户'),
        (3, 'SVIP用户'),
    )
    user_type = models.IntegerField(choices=user_type_choices)
    name = models.CharField(max_length=32, unique=True)
    pwd = models.CharField(max_length=64)
    user_group = models.ForeignKey('UserGroup', on_delete=models.CASCADE)
    role = models.ManyToManyField('Role')


class Token(models.Model):
    user_info = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE)
    token = models.CharField(max_length=64)


class UserGroup(models.Model):
    title = models.CharField(max_length=32)


class Role(models.Model):
    title = models.CharField(max_length=32)

生成的数据表:
在这里插入图片描述
在角色表中添加如下数据:
在这里插入图片描述
原先使用 json.dumps 方法对从数据库中获取到的数据进行序列化:

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/roles/', views.RolesView.as_view()),
]

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json

class RolesView(APIView):
    def get(self, request, *args, **kwargs):
        roles = models.Role.objects.all()
        print(roles)  # <QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>
        roles = models.Role.objects.all().values('id', 'title')
        print(roles)  # <QuerySet [{'id': 1, 'title': '管理员'}, {'id': 2, 'title': '超级管理员'}]>
        roles = list(roles)  # [<Role: Role object (1)>, <Role: Role object (2)>]
        print(roles)  # [{'id': 1, 'title': '管理员'}, {'id': 2, 'title': '超级管理员'}]
        ret = json.dumps(roles, ensure_ascii=False)
        return HttpResponse(ret)

在这里插入图片描述
现在我们可以使用Django REST framework中的序列化来对从数据库中的获取的数据进行序列化:

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers

class MySerializers(serializers.Serializer):
    """
    自定义序列化类
    """
    id = serializers.IntegerField()
    title = serializers.CharField()

class RolesView(APIView):
    def get(self, request, *args, **kwargs):
        roles = models.Role.objects.all()
        # 因为对象不止一个,序列化[obj,obj,obj]这种,要使用many=True
        serializers = MySerializers(instance=roles, many=True)
        print(serializers)
        """
        MySerializers(instance=<QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>, many=True):
        id = IntegerField()
        title = CharField()
        """
        # serializers.data是已经转换完成的结果
        print(serializers.data) # [OrderedDict([('id', 1), ('title', '管理员')]), OrderedDict([('id', 2), ('title', '超级管理员')])]
        
        ret = json.dumps(serializers.data, ensure_ascii=False)
        return HttpResponse(ret)

在这里插入图片描述
对于从数据库中获取一条数据,如果适用序列化:

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers


class MySerializers(serializers.Serializer):
    """
    自定义序列化类
    """
    id = serializers.IntegerField()
    title = serializers.CharField()


class RolesView(APIView):
    def get(self, request, *args, **kwargs):
        roles = models.Role.objects.first()
        # 因为就一个对象,序列化obj,要使用many=False
        serializers = MySerializers(instance=roles, many=False)  # 默认也是False
        print(serializers)
        """
        MySerializers(instance=<Role: Role object (1)>):
        id = IntegerField()
        title = CharField()
        """
        print(serializers.data)  # {'id': 1, 'title': '管理员'}
        # serializers.data是已经转换完成的结果
        ret = json.dumps(serializers.data, ensure_ascii=False)
        return HttpResponse(ret)

在这里插入图片描述

2. 自定义字段

Django REST framework的序列化可以允许我们自定义字段,从数据库中获取字段值也特别方便:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
]
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers

class UserinfoSerializer(serializers.Serializer):
    username = serializers.CharField()
    pwd = serializers.CharField()
    user_type_id = serializers.CharField(source='user_type')  # source对应数据库中字段,row.user_type
    user_type_title = serializers.CharField(source='get_user_type_display')  # row.get_user_type_display()
    group_title = serializers.CharField(source='user_group.title')
    rls = serializers.SerializerMethodField()  # 自定义展示

    def get_rls(self, row):
        row_obj_list = row.role.all()
        ret = []
        for item in row_obj_list:
            ret.append({'id': item.id, 'title': item.title})
        return ret


class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

在这里插入图片描述

3. ModelSerializer

ModelSerializer类继承了Serializer,内部做了一些操作可以自动生成所有的字段:

class UserinfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

在这里插入图片描述
简单的可以直接用数据库的字段适用ModelSerializer生成,复杂的可以自定义:

class UserinfoSerializer(serializers.ModelSerializer):
    user_type_title = serializers.CharField(source='get_user_type_display')
    group_title = serializers.CharField(source='user_group.title')
    rls = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo
        # fields = "__all__"
        fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', 'group_title',]

    def get_rls(self, row):
        row_obj_list = row.role.all()
        ret = []
        for item in row_obj_list:
            ret.append({'id': item.id, 'title': item.title})
        return ret


class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

在这里插入图片描述
生成字段的时候可以额外加一些参数,可以不用再定义group_title:

class UserinfoSerializer(serializers.ModelSerializer):
    user_type_title = serializers.CharField(source='get_user_type_display')
    # group_title = serializers.CharField(source='user_group.title')
    rls = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo
        # fields = "__all__"
        fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', ]
        extra_kwargs = {'group_title': {'source': 'user_group.title'}}  # 和上面自定义一样

    def get_rls(self, row):
        row_obj_list = row.role.all()
        ret = []
        for item in row_obj_list:
            ret.append({'id': item.id, 'title': item.title})
        return ret

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

在这里插入图片描述

4. 深度控制

只需要在Meta中设置 depth 字段就可以 自动序列化连表 获取关联表中的字段:

class UserinfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        """
        depth:0~10,0表示只获取UserInfo中的表中的字段的值
        """
        depth = 1

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

在这里插入图片描述

class UserinfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role']
        depth = 1

在这里插入图片描述

5. 生成链接

Django REST framework中的序列化也可以帮助我们生成超链接:

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
    re_path('(?P<version>[v1,v2]+)/group/(?P<pk>\d+)', views.GroupView.as_view(), name='gp'),
]
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers

class UserinfoSerializer(serializers.ModelSerializer):
    group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_url_kwarg='pk',
                                                 lookup_field='user_group_id')  # pk和url上自定义的pk有关系

    class Meta:
        model = models.UserInfo
        fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role', 'group']
        depth = 1

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True, context={'request': request})
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")


class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserGroup
        fields = '__all__'


class GroupView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')  # url传过来的pk对应/(?P<version>[v1,v2]+)/group/(?P<pk>\d+)/
        obj = models.UserGroup.objects.filter(pk=pk).first()
        group_serializer = GroupSerializer(instance=obj, many=False)
        ret = json.dumps(group_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

在这里插入图片描述
在这里插入图片描述

6. 请求数据校验

Django REST framework序列化还可以做 请求数据校验,简单的数据校验:

class UserGroupSerializer(serializers.Serializer):
    # title = serializers.CharField(error_messages={'required':'dsdsd'})#error_messages暂时没作用
    # 写需要校验的字段
    title = serializers.CharField()


class UserGroupView(APIView):
    def post(self, request, *args, **kwargs):
        print(request.data)  # {'title': ''}
        ser = UserGroupSerializer(data=request.data)
        if not ser.is_valid():
            print(
                ser.errors['title'][0])  # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
        else:
            print(ser.validated_data,
                  type(ser.validated_data))  # OrderedDict([('title', '3组')]) <class 'collections.OrderedDict'>
            print(ser.validated_data['title'])  # 3组
        return HttpResponse()

在这里插入图片描述
在这里插入图片描述

7. 自定义验证规则

简单的数据校验一般不能满足需求,很多情况下需要自定义验证规则校验数据:

class UserGroupValidator:
    def __init__(self, base):
        self.base = str(base)

    def __call__(self, value):
        """数据一提交过来就会执行这个__call__方法"""
        print('提交过来title的值', value)  # value是提交过来的值
        if not value.endswith(self.base):
            message = '标题必须以%s结尾!' % self.base
            raise serializers.ValidationError(message)

    def set_context(self, serializer_field):
        """执行验证之前调用,serializer_field是当前字段对象,这里用不到"""
        pass


class UserGroupSerializer(serializers.Serializer):
    title = serializers.CharField(validators=[UserGroupValidator('组'), ])


class UserGroupView(APIView):
    def post(self, request, *args, **kwargs):
        # print(request.data)  # {'title': '3'}
        ser = UserGroupSerializer(data=request.data)
        if not ser.is_valid():
            print(
                ser.errors['title'][0])  # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
        else:
            print(ser.validated_data,
                  type(ser.validated_data))  # OrderedDict([('title', '3组')]) <class 'collections.OrderedDict'>
            print(ser.validated_data['title'])  # 3组
        return HttpResponse()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
自定义验证规则时,需要用到钩子函数,需要从 is_valid 方法开始找。

8. 源码流程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章