zoukankan      html  css  js  c++  java
  • rest framework 之序列化

    一、示例

    restful work 的序列号就类似于 Django 的 Form 表单。

    1、api/urls.py

    from django.urls import path, re_path
    from api.views import UserView, ParserView, RolesView
    
    urlpatterns = [
        # path('users/', UserView.as_view()),
        re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user'),   # 解析
    
        re_path('(?P<version>[v1|v2]+)/roles', RolesView.as_view()),    # 序列化
    
        path('parser/', ParserView.as_view(), name='api_parer'),
    ]
    
    1. api/views.py
    from django.shortcuts import render, HttpResponse
    from rest_framework.views import APIView
    from rest_framework import serializers
    from app import models
    import json
    
    
    
    class RolesSerializers(serializers.Serializer):
        """序列化类(对应 Role 模型类中字段)"""
        id = serializers.IntegerField()
        name = serializers.CharField()
    
    
    class RolesView(APIView):
        def get(self, request, *args, **kwargs):
            # 取出全部
            # roles = models.Role.objects.all()
            # # 序列化,两个参数,instance:接受Queryset(或者对象)   mangy=True表示处理多个对象,mant=False表示处理单个对象
            # ser = RolesSerializers(instance=roles, many=True)
            # # 转成json格式,ensure_ascii=False表示显示中文,默认为True
            # ret = json.dumps(ser.data, ensure_ascii=False)
    
            # 取出第一个
            role = models.Role.objects.all().first()
            ser = RolesSerializers(instance=role, many=False)
            ret = json.dumps(ser.data, ensure_ascii=False)
            return HttpResponse(ret)
    
    1. app/models.py
    from django.db import models
    
    
    class UserInfo(models.Model):
        USER_TYPE = (
            (1, '普通用户'),
            (2, 'VIP'),
            (3, 'SVIP')
        )
    
        user_type = models.IntegerField(choices=USER_TYPE)
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    
        group = models.ForeignKey('UserGroup', on_delete=models.CASCADE, verbose_name='所属组', null=True, blank=True)
        roles = models.ManyToManyField('Role', verbose_name='角色')
    
    
    class UserToken(models.Model):
        user = models.OneToOneField(UserInfo, on_delete=models.CASCADE)
        token = models.CharField(max_length=64)
    
    
    class UserGroup(models.Model):
        """分组"""
        name = models.CharField(verbose_name='组名', max_length=64)
    
    
    class Role(models.Model):
        """角色"""
        name = models.CharField(max_length=64, verbose_name='角色名')
    
    1. 访问:http://127.0.0.1:8000/api/v1/roles
    {"id": 1, "name": "老板"}
    

    二、进阶

    前面我们只序列化了没有关联的字段,对于多选字段、外键以及多对多字段都没有演示,在这里我们还将学习如何自定义一个序列化方法。

    1、各个数据表数据:

    2、api/urls.py

    from django.urls import path, re_path
    from api.views import UserView, ParserView, RolesView, UserInfoView
    
    urlpatterns = [
        # path('users/', UserView.as_view()),
        re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user'),
    
        re_path('(?P<version>[v1|v2]+)/roles', RolesView.as_view()),    # 序列化
        re_path('(?P<version>[v1|v2]+)/info', UserInfoView.as_view()),  # 序列化
    
        path('parser/', ParserView.as_view(), name='api_parer'),
    ]
    

    3、api/views.py

    class UserInfoSerializers(serializers.Serializer):
        # 多选字段:user_type是choices(1,2,3),显示全称的方法用 get_字段名_display
        type = serializers.CharField(source='get_user_type_display')
        username = serializers.CharField()
        password = serializers.CharField()
        # 外键字段: group.name:组的名字
        group = serializers.CharField(source="group.name")
        # SerializerMethodField(),表示自定义显示
        # 然后写一个自定义的方法
        rls = serializers.SerializerMethodField()
    
        def get_rls(self, row):
            """获取用户所有角色,get_rls 和上面自定义方法名字一致"""
            print(row)  # UserInfo object (2)
            role_obj_list = row.roles.all()
            print(role_obj_list)    # <QuerySet [<Role: Role object (1)>]>
            ret = []
            # 获取角色的id和名字
            # 以字典的键值对方式显示
            for item in role_obj_list:
                ret.append({"id": item.id, "name": item.name})
            return ret
    
    
    class UserInfoView(APIView):
        def get(self, request, *args, **kwargs):
            users = models.UserInfo.objects.all()
            ser = UserInfoSerializers(instance=users, many=True)
            ret = json.dumps(ser.data, ensure_ascii=False)
            return HttpResponse(ret)
    
    1. 访问:http://127.0.0.1:8000/api/v1/info
    [{"type": "普通用户", "username": "rose", "password": "123", "group": "一组", "rls": [{"id": 1, "name": "老板"}]}, {"type": "VIP", "username": "john", "password": "123", "group": "二组", "rls": []}, {"type": "SVIP", "username": "hj", "password": "123", "group": "三组", "rls": [{"id": 4, "name": "普通员工"}]}]
    

    总结

    • 多选字段:使用 get_字段名_display 获取字段原始值
    • 外键字段:source="外键名.要获取的字段名"
    • 多对多字段:可通过自定义分实现
    • 自定义方法:mth = serializers.SerializerMethodField(),方法名:get_mth()

    三、ModelSerializer

    ModelSerializer 效果类似于 Django Form 中的 ModelForm

    class UserInfoSerializers(serializers.ModelSerializer):
        type = serializers.CharField
        group = serializers.CharField(source="group.name")
        rls = serializers.SerializerMethodField()
    
        def get_rls(self, row):
           pass
    
        class Meta:
            model = models.UserInfo
            # fields = '__all__'
            fields = ['id','username','password','type','group','rls']
    

    四、depth 控制连表的深度

    当表与表之间多个相连,如果只想显示前面几层,可以使用 depth 控制连表的深度:

    class UserInfoSerializers(serializers.ModelSerializer):
        type = serializers.CharField
        group = serializers.CharField(source="group.name")
        rls = serializers.SerializerMethodField()
    
        def get_rls(self, row):
           pass
    
        class Meta:
            model = models.UserInfo
            # fields = '__all__'
            fields = ['id','username','password','type','group','rls']
            depth = 1       # 控制为 1 层
    

    六、HyperlinkedidentityField 生成 url

    序列化关联数据表的相应字段的 url,就像下面这种:

    [
        {
            "id": 1,
            "publish": "http://127.0.0.1:8080/api/publish/1",
            "name": "红楼梦",
            "price": "123.00",
            "publish_date": null
        },
        {
            "id": 2,
            "publish": "http://127.0.0.1:8080/api/publish/2",
            "name": "西游记",
            "price": "234.00",
            "publish_date": null
        }
    ]
    

    1、api/serializers.py

    from rest_framework import serializers
    from app import models
    
    
    class UserInfoSerializers(serializers.ModelSerializer):
        """用户个人信息序列化"""
        group = serializers.HyperlinkedIdentityField(view_name='gob', lookup_field='group_id', lookup_url_kwarg='pk')
    
        class Meta:
            model = models.UserInfo
            fields = '__all__'
    
    
    class RolesSerializers(serializers.Serializer):
        """序列化类"""
        id = serializers.IntegerField()
        name = serializers.CharField()
    
    
    class GroupSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserGroup
            fields = "__all__"
    

    参数:

    • view_name:关联路由 URL 中的 name 参数值,用来反向解析 URL
    • lookup_field:要查找的目标字段,如:group_idUserInfo 模型中的外键字段(即我们要查找的字段)
    • lookup_url_kwarg:关键字参数的名称,该参数对应于查找字段,一般为 pk

    2、api/urls.py

    from django.urls import path, re_path
    from api.views import UserView, ParserView, RolesView, UserInfoView, GroupView
    
    urlpatterns = [
        re_path('(?P<version>[v1|v2]+)/info/', UserInfoView.as_view()),  # 序列化
    
        re_path('(?P<version>[v1|v2]+)/group/(?P<pk>d+)/', GroupView.as_view(), name='gob'),  # 序列化生成url
    
    ]
    

    3、api/views.py

    from django.shortcuts import render, HttpResponse
    from rest_framework.views import APIView
    from rest_framework.parsers import JSONParser, FormParser
    
    from .serializers import GroupSerializer, RolesSerializers, UserInfoSerializers
    
    from app import models
    from django.http import JsonResponse
    
    
    class UserInfoView(APIView):
        def get(self, request, *args, **kwargs):
            users = models.UserInfo.objects.all()
            # 这里必须指定 context,将 request 传递给 UserInfoSerializers
            user_ser = UserInfoSerializers(instance=users, many=True, context={'request': request})
            return JsonResponse(user_ser.data, safe=False)
    
    
    class GroupView(APIView):
        def get(self, request, *args, **kwargs):
            # pk = kwargs.get('pk')
            # group = models.UserGroup.objects.filter(pk=pk).first()
            #
            # group_ser = GroupSerializer(instance=group, many=False)
            # # ret = json.dumps(ser.data, ensure_ascii=False)
            # return JsonResponse(group_ser.data, safe=False)
            return HttpResponse('ok')
    

    4、访问:http://127.0.0.1:8000/api/v2/info/

    [
        {
            "id": 1,
            'username': 'rose', john/hj
            'password': '123',
            "group": "http://127.0.0.1:8080/api/group/1",
            "roles": [
                2,
            ]
        },
        {
            "id": 2,
            'username': 'john', 
            'password': '123',
            "group": "http://127.0.0.1:8080/api/group/2",
            "roles": [
                1,
            ]
        },
    ]
    

    七、用户请求数据验证

    验证用户请求的数据是否合法

    1、api/serializers.py

    from rest_framework import serializers
    
    
    class UserGroupSerializers(serializers.Serializer):
        """用户请求验证"""
        title = serializers.CharField()
    

    2、api/views.py

    from django.shortcuts import render, HttpResponse
    from rest_framework.views import APIView
    
    
    from .serializers import GroupSerializer, RolesSerializers, UserInfoSerializers, UserGroupSerializers
    
    class UserGroupView(APIView):
        """用户请求验证"""
        def post(self, request, *args, **kwargs):
            usergroup_ser = UserGroupSerializers(data=request.data)
            if usergroup_ser.is_valid():
                print(usergroup_ser.validated_data['title'])
            else:
                print(usergroup_ser.errors)
            return HttpResponse('用户提交数据错误')
    

    3、利用 postman 模拟用户请求发送数据

    请求方式 post,参数格式 JSON:

    当请求的数据为空时,会自动验证数据的合法性:

    八、自定义验证规则

    你可以自定义验证规则,比如验证用户输入的字段必须以什么开头,必须是邮箱格式等:

    1、api/serializers.py

    class GroupValidation:
        """自定义验证规则"""
        def __init__(self, base):
            self.base = base    # love
    
        def __call__(self, value, *args, **kwargs):
            if not value.startswith(self.base):
                msg = '标题必须以 %s 开头' % self.base
                raise serializers.ValidationError(msg)
    
    
    class UserGroupSerializers(serializers.Serializer):
        """用户请求数据验证"""
        # title = serializers.CharField()
        title = serializers.CharField(validators=[GroupValidation('love'), ])
    

    2、其余的不变,现在验证规则按照我们设置的走,错误提示也一样:

  • 相关阅读:
    更博不能忘——webpack学习笔记
    面试中遇到过的闭包~
    github踩坑之git命令收集与整理(windows)
    应该写个博客
    重学C语言(一):熟悉汇编语言
    关于Swift的闭包(closure)以及其在可选(Optional)类型中的应用
    解决Xcode 7出现cdtool cannot compile的问题(2015年8月12日更新)
    更改LaTeX的数学模式中使用的字体
    在Mac下安装使用支持中文的LaTeX(二)
    在Mac下安装使用支持中文的LaTeX(一)
  • 原文地址:https://www.cnblogs.com/midworld/p/11380194.html
Copyright © 2011-2022 走看看