• 序列化组件


    序列化组件

    我们在使用json进行数据的序列化操作时,只能对基本数据类型进行序列化

    当需要序列化的是对象是比如QuerySet对象,我们只能循环取出每个对象将具体属性放到字典中后进行序列化操作。步骤较为复杂,如下所示

    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自带序列化组件

    from django.core import serializers
    def test(request):
        book_list = Book.objects.all()    # queryset对象
        ret = serializers.serialize("json", book_list)
        return HttpResponse(ret)
    

    rest-framework序列化之Serializer

    models.py

    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name
    

    serializers.py

    -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 --->是一个字典

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

    可以不用source,直接用 字段名 当变量名,必须为字段名

    也可以用 source来指定需要的目标字段 (推荐,尽量让字段名不要泄露)

    source`也可以用来指定模型层中的方法

    一对多关联关系,可以在 source 中用 .来指定字段,例如取出版社名字,用 source='publish.name'

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

    多对多要用SerializerMethodField(),然后定义一个get_变量名的方法,方法名字必须为 get_变量名

    get_变量名方法要传参,传入当前对象,例如在 BookSerializer 中就是book对象

    get_变量名方法中,也可以对数据进行序列化,例如取书的所有作者,就可以对作者序列化然后 return

    from rest_framework import serializers
    
    class BookSerializers(serializers.Serializer):
        title=serializers.CharField(max_length=32)
        price=serializers.IntegerField()
        pub_date=serializers.DateField()
        publish=serializers.CharField(source="publish.name")
        #authors=serializers.CharField(source="authors.all")
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            temp=[]
            for author in obj.authors.all():
                temp.append(author.name)
            return temp
      #此处可以继续用author的Serializers,
      # def get_authors(self,obj):
        #     ret=obj.authors.all()
        #     ss=AuthorSerializer(ret,many=True)
        #     return ss.data
    

    继承serializers.Serializer详解
    继承serializers.ModelSerializer

    from app01 import models
    class PublishSerializers(serializers.ModelSerializer):
        class Meta:
            model=models.Publish
            fields='__all__'
    
            # 指定只取这两个字段
            #fields = ['nid','name']
            # 去掉指定的字段
            # exclude=['publish','authors']
            # fields,跟exclude不能连用
            # 指定深度,就是跨几个表(官方建议小于10,我给你的建议小于3)
            # depth = 2
            # read_only_fields指明只读字段, 仅用于序列化输出的字段. 
            # write_only_fields指明只读写段, 仅用于反序列化输入的字段.
            # 可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数 
            # extra_kwargs = {  'bread': {'min_value': 0, 'required': True},    
            #                              'bcomment': {'min_value': 0, 'required': True}, } 
    

    view.py:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import *
    from django.shortcuts import HttpResponse
    from django.core import serializers
    
    
    
    class BookViewSet(APIView):
    
        def get(self,request,*args,**kwargs):
            book_list=Book.objects.all()
            # 序列化方式1:
            # from django.forms.models import model_to_dict
            # import json
            # data=[]
            # for obj in book_list:
            #     data.append(model_to_dict(obj))
            # print(data)
            # return HttpResponse("ok")
    
            # 序列化方式2:
            # data=serializers.serialize("json",book_list)
            # return HttpResponse(data)
    
            # 序列化方式3:
            bs=BookSerializers(book_list,many=True)     #many=True代表有多条数据,如果只有一条数据,many=False
            return Response(bs.data)
         # 序列化方式4: 
          # ret=models.Book.objects.all().values('nid','title')
         # dd=list(ret)
            # return HttpResponse(json.dumps(dd))
    
    

    注意:

    source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))

    choice的用法:
    -拿出数字对应的中文:get _ 字段名 _ dispaly()

    如在模型中定义一个方法,直接可以在在source指定执行

    class UserInfo(models.Model):
        user_type_choices = (
            (1,'普通用户'),
            (2,'VIP'),
            (3,'SVIP'),
        )
        user_type = models.IntegerField(choices=user_type_choices)
    
        username = models.CharField(max_length=32,unique=True)
        password = models.CharField(max_length=64)
    
    
    #视图
    ret=models.UserInfo.objects.filter(pk=1).first()
    aa=ret.get_user_type_display()
    
    #serializer
    xx=serializers.CharField(source='get_user_type_display')
    

    rest-framework序列化之ModelSerializer

    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # fields = "__all__"
            fields=['nid','title','authors','publish']
            # exclude=('nid',)   #不能跟fields同时用
            # depth = 1    #深度控制,写 几 往里拿几层表的数据,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
        publish=serializers.SerializerMethodField()
        def get_publish(self,obj):
            return obj.publish.name
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            ret=obj.authors.all()
            ss=AuthorSerializer(ret,many=True)
            return ss.data
    		
    

    小结:

    反序列化的目的是为了调用反序列化对象的save方法

    保存和更新:(必须继承ModelSerializer)
    -保存
    -ser=BookSerializer(data=request.data)
    -ser.save()---->向数据库中插一条数据
    -更新
    -ser=BookSerializer(data=request.data.instance='要更新的对象')
    -ser.save()---->向数据库中插一条数据

    APIView类说明

    APIView 类
    		-继承了View
    		-重写了as_view方法,在内部屏蔽了xsrf
    		-重写了dispatch方法---核心
    Request 类
    	-封装了原来的request
    	-request.data   --->前台传递过来的数据,放在里面
    	-request重写了__getattr__方法
    	-request.query_params   就是原来request.的GET
    

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

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

    • 序列化组件校验和forms组件类似(validate->clean)

    • 钩子函数抛异常,异常是 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()
      

      方式二:

      ret = models.Book.objects.filter(name=request.data.get('name')).first()
      ser=BookSerializer(data=request.data)
      if ser.is_valid():
        ser.updata(instance=ret')
      
  • 相关阅读:
    蓝桥杯 矩阵翻硬币
    2018 南京预选赛 J Sum ( 欧拉素数筛 、Square-free Number、DP )
    HDU 3826 Squarefree number ( 唯一分解定理 )
    HDU 5727 Necklace ( 2016多校、二分图匹配 )
    HDU 5726 GCD (2016多校、二分、ST表处理区间GCD、数学)
    hihocoder 1457 后缀自动机四·重复旋律7 ( 多串连接处理技巧 )
    后缀自动机 ( SAM ) 模板
    2018 焦作网络赛 K Transport Ship ( 二进制优化 01 背包 )
    2018 焦作网络赛 G Give Candies ( 欧拉降幂 )
    蓝桥杯 买不到的数目 ( 裴蜀定理 )
  • 原文地址:https://www.cnblogs.com/9527mwz/p/11200569.html
Copyright © 2020-2023  润新知