• Django框架(十九)—— drf:序列化组件(serializer)


    序列化组件

    # 模型层
    from django.db import models
    
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField()
    
        publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)
    
    
    class AuthorDatail(models.Model):
        nid = models.AutoField(primary_key=True)
        telephone = models.BigIntegerField()
        birthday = models.DateField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    
        def test(self):
            return self.email
    
    

    一、利用for循环来实现序列化(繁琐)

    def get(self, request):
        response = {'status': 100, 'data': None}
        ll = [{'name': book.name, 'price': book.price} for book in books]
        # 返回数据是json格式数据
        response['data'] = ll
        # safe = True 表示数据可以是列表
        return JsonResponse(response, safe=False)
    

    二、利用Django提供的序列化组件(不可控需要的字段)

    Django内置的serializers

    from django.core import serializers
    
    def get(self,request):
        books = models.Book.objects.all()
    	ret=serializers.serialize('json','queryset对象')
        #ret就是序列化之后的字符串了,不需要再序列化了
        return HttpResponse(ret)
    

    三、利用drf提供的序列化组件

    1、基于Serializer类实现序列化——基本语法

    -1 先导入
    	from rest_framework.serializers import Serializer
    	from rest_framework import serializers
    -2 写一个类,继承Serializer
    -3 在类内部写属性:
    	name=serializers.CharField()
    -4 使用:
     	先生成对象,需要传参数 instance:要序列化的对象(可能是queryset,也可能是单个对象)    
    	many:如果是queryset---True,,如果是单个对象--False
    -5 序列化的数据:对象.data --->是一个字典
    
    
    from rest_framework.views import APIView
    from rest_framework import serializers
    
    
    class BookSerializer(serializers.Serializer):
        name = serializers.CharField()
    
    
    class Book(APIView):
        def get(self, request):
            # 要序列化的对象(可以是queryset,也可以是单个对象)
            # book = models.Books.objects.filter(name='红楼梦').first()
            # ser = BookSerializer(instance=book,many=False)
            books = models.Books.objects.all()
            ser = BookSerializer(instance=books, many=True)
            data = ser.data
            return JsonResponse(data, safe=False)
    
    

    2、基于Serializer类实现序列化——高级语法

    (1)非关联字段或一对多字段

    • 可以不用source,直接用 字段名 当变量名,必须为字段名
    • 也可以用 source来指定需要的目标字段 (推荐,尽量让字段名不要泄露)
    • source也可以用来指定模型层中的方法
    • 一对多关联关系,可以在 source 中用 .来指定字段,例如取出版社名字,用 source='publish.name'
    from rest_framework.views import APIView
    from rest_framework import serializers
    
    
    class BookSerializer(serializers.Serializer):
        # 利用source来指定魔表字段,给key取别名
        aaa = serializers.CharField(source='name')  # 等价于 name = serializers.CharField()
        price = serializer.CharField()
        publish_name = serializer.CharField(source='publish.name')
        # source 也可以用来指定模型层中的方法
        t = serializer.CharField(source='publish.test')
        
        
    class Book(APIView):
        def get(self, request):
            books = models.Books.objects.all()
            ser = BookSerializer(instance=books, many=True)
            data = ser.data
            return JsonResponse(data, safe=False)
        
    

    (2)一对多或者多对多字段

    • 多对多要用SerializerMethodField(),然后定义一个get_变量名的方法,方法名字必须为 get_变量名
    • get_变量名方法要传参,传入当前对象,例如在 BookSerializer 中就是book对象
    • get_变量名方法中,也可以对数据进行序列化,例如取书的所有作者,就可以对作者序列化然后 return
    from rest_framework.views import APIView
    from rest_framework import serializers
    
    # 用于对author的数据进行序列化
    class AuthorSerializer(serliazer.Serializer):
        name = serializer.CharField()
        age = serializer.CharField()
    
    
    class BookSerializer(serializers.Serializer):
        # 利用source来给key取别名
        aaa = serializers.CharField(source='name')  # 等价于 name = serializers.CharField()
        price = serializer.CharField()
        
        # book和publish是一对多的关系,也可以用SerializerMethodField
        publish = serializer.SerializerMethodField()
        def get_publish(self, book):
           pub = book.publish.name
           return pub
        
        # book和authors是多对多的关系,用SerializerMethodField
        au = serializer.SerializerMethodField()
        def get_au(self, obj):
            aus = obj.authors.all()
            ll = []
            for obj_au in aus:
                ll.append({'au_name':obj_au.name,'au_age':obj_au.age})
        	return ll
        
        # 也可以在方法中使用序列化类序列化
        '''
        def get_au(self, book):
        	# 获取这本书的所有作者
            aus = book.authors.all()
            # 可以在方法中对authors的数据进行序列化
            au_ser = AuthorSerializer(aus,many=True)
            return au_ser.data
        '''
    
        
        
    class Book(APIView):
        def get(self, request):
            books = models.Books.objects.all()
            ser = BookSerializer(instance=books, many=True)
            data = ser.data
            return JsonResponse(data, safe=False)
        
    

    3、基于ModelSerializer类实现序列化

    (1)基本语法

    from app01.models import Book
    
    # 这样序列化得到的数据,authors是中都是author_id
    class BookSerializer(serializer.ModelSerializer):
        class Meta:
            model = Book
            fields = '__all__'
    

    (2)重写属性

    from app01.models import Book
    
    # 这样序列化得到的数据,authors中都是author_id,publish也是publish_id
    class BookSerializer(serializer.ModelSerializer):
        class Meta:
            model = Book
            fields = '__all__'
        # 重写属性authors和publish
        puhlish = serializer.CharField(source='publish.name')
        authors = serializers.SerializerMethodField()
        def get_authors(self,book):
            aus = book.authors.all()
            # 可以在方法中对authors的数据进行序列化
            au_ser = AuthorSerializer(aus,many=True)
            return au_ser.data
    

    (3)其他属性

    • fields = ['id','name'] ---------> 指定序列化这两个字段
    • exclude = ['publish','create_time'] ----------> 除了这两个字段外,其余的序列化
    • depth = 2 ----------> 指定深度,即跨表。值为1表示跨一次表;值为2表示跨两次表
    class BookSerializer(serializers.ModelSerializer):
        # 必须写一个内部类,名字叫Meta
        class Meta:
            model = Book
            # fields = '__all__'
            # 指定只取这两个字段
            fields = ['nid','name']
            # 去掉指定的字段
            # exclude=['publish','authors']
            # fields,跟exclude不能连用
            # 指定深度(官方建议小于10,我给你的建议小于3)
            depth = 2
    
    

    4、HyperlinkedIdentityField(带链接的序列化)-----很少用

    # url层
    url(r'book/$',views.Book.as_view()),
    url(r'publish/(?P<pk>d+)',views.Publish.as_view(),name='ttt')
    
    # view层
    # 定义一个序列化类
    class BookSerializer(serializers.Serializers):
        name = serializers.CharField()
        # view_name:路由的名字;lookup_field:根据表的哪个字段;lookup_url_kwarg:反向解析有名分组的名字。------lookup_field与lookup_url_kwarg相当于是key与value
        publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id',lookup_url_kwarg='pk')
        # 最后得到的链接是: http://127.0.0.1:8000/publish/1
    
    # CBV 
    class Book(APIView):
        def get(self, request):
            books = models.Book.objects.all()
            # 必须要传过去request,以便在链接中拼接域名
            ser = BookSerializer(books, many=True, context={'request':request})
            return JsonResponse(ser.data,safe=False)
    
    

    5、序列化组件之请求数据校验和保存功能

    • 序列化类必须继承ModelSerializer类,只有该类可以指定数据保存修改的目标表模型。倘若一定要继承Serializer类,可以通过重写save方法,来实现保存和修改数据

    • 序列化组件校验和forms组件类似

    • 钩子函数抛异常,异常是 rest_framework.exceptions 下的 ValidationError

    • 新增数据:
      新增数据,将数据传入实例化类产生对象,通过is_valid()校验,校验通过,利用序列化对象的save()方法保存

      ser=BookSerializer(data=request.data)
      if ser.is_valid():
      	ser.save()
      
    • 修改数据:
      修改数据一定要在实例化序列化类的时候传参instance='要修改的对象'指定要修改的对象

      ret = models.Book.objects.filter(name=request.data.get('name')).first()
      ser=BookSerializer(data=request.data, instance=ret')
      if ser.is_valid():
      	ser.save()
      
    # 定义一个序列化类
    from rest_framework.exceptions import ValidationError
    class BookSerializer(serializerss.ModelSerializer):
        class Meta:
    	    model = Book
        	fields = '__all__'
        # 校验和forms组件类似    
        name = serializers.CharField(max_length=10,required=True,error_message={'max_length':最长不能超过10位,'requered':'必须填'})
        # 局部钩子,value是前端传过来的数据
        def validate_name(self,value):
            if value.startswith('aa'):
                raise ValidationError('不能以aa开头')
            return value
        # 全局钩子 ,这里的value是上面验证通过后的所有数据构成的字典
        def validate(self,value):
            pwd = value.get('pwd')
            re_pwd = value.get('re_pwd')
            if pwd == re_pwd:
                return value
            raise ValidationError('两次密码不一致')
    
    
    # CBV  
    # 1. 新增对象
    class Book(APIView):
        def post(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': None}
            data = request.data
            ser = BookSerializer(data=data)
            if ser.is_valid():
                ser.save()
                response['msg'] = '创建成功'
            else:
                response['status'] = 101
                response['msg'] = ser.errors
            return JsonResponse(response, safe=False)
    
    
    # CBV
    # 2.修改数据
    class Book(APIView):
        def put(self, request, *args, **kwargs):
            response = {'status': 100, 'msg': None}
            data = request.data
            ser = BookSerializer(data=data,instance=)
            if ser.is_valid():
                ser.save()
                response['msg'] = '创建成功'
            else:
                response['status'] = 101
                response['msg'] = ser.errors
            return JsonResponse(response, safe=False)
    
  • 相关阅读:
    CentOS 安装Python3, pip3
    Pyinstaller打包python程序,以及遇到的问题:Cannot find existing PyQt5 plugin directories
    [Python] fetchone()和fetchall()
    在Linux命令行下,如何登录mysql server
    管理MySQL的客户端软件-MySQL Workbench
    在win10修改jupyter notebook(Anaconda安装)工作路径
    安装spark过程中出现Exception in thread "main" java.lang.UnsupportedClassVersionError错误的解决办法
    如何在win10本地主机操作系统和virtualBox 的Ubuntu之间设置共享文件夹
    支持向量机(SVM)
    特征工程(python)
  • 原文地址:https://www.cnblogs.com/linagcheng/p/10104270.html
Copyright © 2020-2023  润新知