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方法





posted @ 2018-07-29 21:11  龙云飞谷  阅读(205)  评论(0编辑  收藏  举报