zoukankan      html  css  js  c++  java
  • django restframework序列化

    序列化

    序列化用于对用户请求数据进行验证和数据进行序列化,序列化器(serializers)类似于Django forms

    模型设计

    from django.db import models
    
    # Create your models here.
    class User(models.Model):
        """
        用户信息
        """
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        level_choices = (
            (1, 'common'),
            (2, 'vip'),
            (3, 'svip')
        )
        level = models.PositiveSmallIntegerField(choices=level_choices, default=1)
    
        group = models.ForeignKey(to='Group')
        roles = models.ManyToManyField(to='Role')
    
        def __str__(self):
            return self.name
    
    class UserToken(models.Model):
        """
        用户令牌
        """
        user = models.OneToOneField(to=User)
        token = models.CharField(max_length=64)
    
        def __str__(self):
            return self.token
    
    class Role(models.Model):
        """
        角色
        """
        r_name = models.CharField(max_length=32, verbose_name='角色名')
    
        def __str__(self):
            return self.r_name
    
    class Group(models.Model):
        """组"""
        g_name = models.CharField(max_length=32, verbose_name='组名称')
    
        def __str__(self):
            return self.g_name
    

    序列化

    序列化一般可以继承两个类,serializers.ModelSerializerserializers.Serializer。继承 serializers.Serializer需要手写字段,继承serializers.ModelSerializer 可以复用数据库字段,并且可以创建和更新数据。

    serializers.Serializer

    class GroupSerializer(serializers.Serializer):
        """
        用户序列化类
        """
        # g_name 名称和数据库表Group的字段名称需要一致
        g_name = serializers.CharField()
    

    serializers.ModelSerializer

    class UserSerializer(serializers.ModelSerializer):
        """
        {
        "code": 1000,
        "data": [
            {
                "id": 1,
                "name": "jack",
                "pwd": "123",
                "level": 3,
                "group": 1,
                "roles": [
                    1,
                    2
                ]
            },
            {
                "id": 2,
                "name": "lily",
                "pwd": "123",
                "level": 1,
                "group": 2,
                "roles": [
                    2
                ]
            },
            {
                "id": 3,
                "name": "lisa",
                "pwd": "123",
                "level": 1,
                "group": 3,
                "roles": [
                    4
                ]
            }
        ],
        "error": null
    }
        """
        class Meta:
            model = User
            # fields 也可以接受一个列表
            fields = '__all__'
    

    source

    source只能得到单个值,不能处理多对多字段

    class UserSerializer(serializers.ModelSerializer):
        level = serializers.CharField(source='get_level_display')
        # group 名称和数据库表一样会覆盖,不一样(写成g_name)就会显示g_name 和 group 两个
        group = serializers.CharField(source='group.g_name')
    
        class Meta:
            model = User
            # fields 也可以接受一个列表
            fields = ['level', 'group', 'roles', 'name', 'pwd','id']
    

    多对多字段

    class UserSerializer(serializers.ModelSerializer):
        level = serializers.CharField(source='get_level_display')
        # group 名称和数据库表一样会覆盖,不一样(写成g_name)就会显示g_name 和 group 两个
        group = serializers.CharField(source='group.g_name')
        roles = serializers.SerializerMethodField()
    
        class Meta:
            model = User
            # fields 也可以接受一个列表
            fields = ['level', 'group', 'roles', 'name', 'pwd','id']
    
        def get_roles(self, obj):
            return [i.r_name for i in obj.roles.all()]
    
    class UserSerializer(serializers.ModelSerializer):
        level_name = serializers.CharField(source='get_level_display', read_only=True)
        # group 名称和数据库表一样会覆盖,不一样(写成g_name)就会显示g_name 和 group 两个
        group_name = serializers.CharField(source='group.g_name', read_only=True)
        roles = serializers.SerializerMethodField()
    
        class Meta:
            model = User
            # fields 也可以接受一个列表
            fields = ['level', 'group', 'roles', 'name', 'pwd','id']
            # depth = 1  # 所有有关系的字段都变成 read_only
            # exclude = []  # 排除某个字段
            # 每个字段的一些额外参数, 下面表示上面定义的fields中的level和group通过get请求的时候不显示,但是post请求创建数据的时候还是可以提供的
            extra_kwargs = {  
                'group': {'write_only': True},
                'level': {'write_only': True},
            }
    
        def get_roles(self, obj):
            return [i.r_name for i in obj.roles.all()]
    

    超链接API:Hyperlinked

    class UserSerializer(serializers.ModelSerializer):
        group = serializers.HyperlinkedIdentityField(
            view_name='sg',   
            lookup_field='group_id',
            lookup_url_kwarg='pk'
        )
        class Meta:
            model = User
            # depth = 1
            # fields 也可以接受一个列表
            fields = ['level', 'group', 'roles', 'name', 'pwd','id']
    

    对应的urls.py的url: url(r'group/(?P<pk>d+)$', SingleGroupView.as_view(), name='sg')

    views.py

    class UserView(APIView):
        """用户视图"""
        def get(self, request, *args, **kwargs):
            ret = {'code': 1000, 'data':None, 'error': None}
            users = User.objects.all()
            try:
                users = User.objects.all()
                # 单个对象many=False
                gs = UserSerializer(users, many=True)
                ret['data'] = gs.data
            except Exception as e:
                ret['code'] = 1001
                ret['error'] = '发生错误'
            return Response(ret)
    
        def post(self, request, *args, **kwargs):
            ret = {'code': 1000, 'data': None, 'error': None}
            # request.data 是一个纯正的字典
            gs = UserSerializer(data=request.data)
            if gs.is_valid():
                # gs.validated_data 是rderedDict,因为roles字段重写成SerializerMethodField,
                # 所以默认的validated_data是获取不到值的,需要手动赋值
                gs.validated_data['roles'] = request.data['roles']
                # 会自动调用create , update 具体是什么方法根据传的参数来定
                gs.save()
                ret['data'] = request.data
            else:
                ret['error'] = gs.errors
            return Response(ret)
    
        def put(self, request, pk):
            user_obj = User.objects.filter(pk=pk).first()
            bs = UserSerializer(user_obj, data=request.data, context={'request': request})
            if bs.is_valid():
                bs.save()
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)
    

    其中gs.data是列表套有序字典的形式,通过Response会做简单的转换成列表套普通字段的形式

    重写create和update

    class UserSerializer(ModelSerializer):
        class Meta:
            model = User
            fields = '__all__'
        def create(self, validated_data):
            roles_list = validated_data.pop('roles')
            group = validated_data['group']['g_name']
            level = validated_data.pop('get_level_display')
            validated_data.pop('group')
            obj = User.objects.create(group_id=group, level=level, **validated_data)
            obj.roles.add(*roles_list)
            return obj
        
        
        def update(self, instance, validated_data):
            group = validated_data['group']['g_name']
            validated_data.pop('group')
            validated_data['group_id'] = group
            if 'get_level_display' in validated_data:
                validated_data['level'] = validated_data.pop('get_level_display')
        
            for attr, value in validated_data.items():
                setattr(instance, attr, value)
            instance.save()
        
            return instance
    

    自定义验证字段

    class XXValidator(object):
        def __init__(self, base):
            self.base = base
    
        def __call__(self, value):
            if not value.startswith(self.base):
                message = '标题必须以 %s 为开头。' % self.base
                raise serializers.ValidationError(message)
    
        def set_context(self, serializer_field):
            """
            This hook is called by the serializer instance,
            prior to the validation call being made.
            """
            # 执行验证之前调用,serializer_fields是当前字段对象
            pass
    
    class UserGroupSerializer(serializers.Serializer):
        # title必须以jack开头,否则调用is_valid()就无法通过
        title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[XXValidator('jack'),])
    

    源码流程

    实例化序列类对象的时候,先执行__new__,再执行__init__,根据many的不同分别调用Serializer类处理和ListSerializer类处理。ser.data会调用这两个对象的to_representation方法





  • 相关阅读:
    网络基础
    Web开发几种常用工具
    win组合键概述(windows10)
    Alfred使用
    Java8之新特性--modules
    jsp九大内置对象和四大作用域
    authtype
    Myeclipse中的快捷键
    如何在Jenkins CI 里调试
    写好unit test的建议和例子
  • 原文地址:https://www.cnblogs.com/longyunfeigu/p/9387576.html
Copyright © 2011-2022 走看看