zoukankan      html  css  js  c++  java
  • REST-Framework: 序列化组件

    目录

    序言:Django自带序列化组件

    一、restframework介绍

    什么是restframework

    restframework介绍

    HTTP动词

    状态码

    二 rest-framework序列化之Serializer

    序列化的意义:

    常用字段类型:

    序列化实例

    三 rest-framework序列化之ModelSerializer

    四 生成hypermedialink(极少数)

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

    序列化组件源码分析


    序言:Django自带序列化组件

    也就是使用原生的django来处理请求

    详见

    在正式开始介绍Rest-Framework之前我们需要对它有一定的了解:

    一、restframework介绍

    什么是restframework

    django restframework是基于django和restful协议开发的框架,在restful协议里,一切皆是资源,操作是通过请求方式控制,可以将python中的对象转换成json格式的字符串

    restframework介绍

    在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

    增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    删:判断要删除的数据是否存在 -> 执行数据库删除
    改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    查:查询数据库 -> 将数据序列化并返回
    Django REST framework可以帮助我们简化上述两部分的代码编写,大大提高REST API的开发速度。

    HTTP动词

    对于资源的具体操作类型,由HTTP动词表示。

    常用的HTTP动词有下面四个(括号里是对应的SQL命令)。

    GET(SELECT):从服务器取出资源(一项或多项)。
    POST(CREATE):在服务器新建一个资源。
    PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
    DELETE(DELETE):从服务器删除资源。
    还有三个不常用的HTTP动词。

    PATCH(UPDATE):在服务器更新(更新)资源(客户端提供改变的属性)。
    HEAD:获取资源的元数据。
    OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

    状态码

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功

    更多状态码看这里:更多的状态码

    下面我们主要介绍使用CBV在视图中处理请求的方式来, 

    在这里我们还是简单说一下,为什么使用CBV而不采用FBV:

    之前介绍Django的时候我们使用的基本上都是FBV, 虽然函数简单明了,但如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了CBV。可以让我们用类写View,然后通过反射执行as_view()方法,这样做的优点主要下面两种:

    提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
    可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性

    下面我就正式开始介绍使用rest-framework在Django中处理请求,

    注意:
    1.记得使用之前没有安装Djangorestframework模块的要安装好该模块
    2.安装成功之后一定要在setting中将rest_framework注册之后才能正常使用

    二 rest-framework序列化之Serializer

    序列化的意义:

    web有两种应用模式,一种是前后端不分离,一种是前后端分离,当前后端分离的时候,后端只需要向前端传输数据即可,不需要进行其他的操作,而restframework在前后端传输数据时,主要是json数据,过程中就要需要把其他数据转换成json数据,比如数据库查询所有数据时,是queryset对象,那就要把这对象处理成json数据返回前端,一般如果是中大型公司,都是前后端分离,这也是目前的市场规则需要.

    然后我们来看序列化时常用的字段和通用参数:

    常用字段类型:

    常用字段类型
    字段  字段构造方式和参数默认值
       BooleanField BooleanField()
    NullBooleanField NullBooleanField
    CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
    EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
    SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
    URLField URLField(max_length=200, min_length=None, allow_blank=False)
    IntegerField IntegerField(max_value=None, min_value=None)
    FloatField FloatField(max_value=None, min_value=None)
    DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)
    max_digits: 最多位数
    decimal_palces: 小数点位置
    DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
    DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
    TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
    DurationField DurationField()
    ChoiceField ChoiceField(choices)
    choices与Django的用法相同
    FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
    ListField ListField(child=, min_length=None, max_length=None)
    DictField DictField(child=)

    相对而言,常用字段类型是比较常见的,在我们的ORM模式里,只要是连接数据库那么就一定需要定义我们的模型参数,下面介绍静态常用的模型参数

    通用参数
     

    参数名称 说明
    max_length 最大长度
    min_lenght 最小长度
    read_only 表明该字段仅用于序列化输出,默认False
    write_only 表明该字段仅用于反序列化输入,默认False
    required 表明该字段在反序列化时必须输入,默认True
    default 反序列化时使用的默认值
    allow_null 表明该字段是否允许传入None,默认False
    validators 该字段使用的验证器
    error_messages 包含错误编号与错误信息的字典
    label 用于HTML展示API页面时,显示的字段名称
    help_text 用于HTML展示API页面时,显示的字段帮助提示信息

    这里比较常用的字段是前面六个,其中max_length和min_length一般配合着charfield使用,可以给该字段设置大小上下限。而read_only和write_only是两个相反的概念,前者是不接收客户端的数据,只向客户端输出数据,后者是只接收客户端的数据,不向客户端输出数据,这就可以类比于我们登录注册时的密码框,我们只需要向它写入而并不需要它像我们输出,并且该字段是经过hash加密的,寻常情况难以解密

    序列化实例

    Models部分:
    首先在应用的models中建立原始的数据库模型

    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

    view部分:

    在对数据库中取出来的数据进行序列化的时候的步骤:

    • 需要写一个类来继承serializers.Serializer, 这个类可以单独写一个文件(建议), 也可以直接在view中书写,

    • 书写的这个类中序列化的字段要和数据库中字段要保持高度一致

    不一致的时候我们就要介绍一下在序列化的时候使用到的一个参数source:
    source可以在后面指定要序列化的字段, 然后再序列化的类中字段就可以自己命名了
     1 变量名和source指定的值不能一样
     2 source='publish.name'还支持继续使用点语法
     3 source 还支持方法(没啥用)
     4 支持写方法对字段进行序列化, 如下
               方法的返回值,会赋给前面定义的序列化的字段名字
               方法一定传一个参数,是当前序列化的表对象
               写方法的时候时固定写法,get_字段名(self, obj):pass
                publish_dic=serializers.SerializerMethodField()
                def get_publish_dic(self,obj):
                        这个obj是当前book对象.
                        return {'id':obj.publish.pk,'name':obj.publish.name}

    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
    
    
    
    
    
    from rest_framework import serializers
    
    # 为序列化做准备
    
    class BookSerializers(serializers.Serializer):
    
    title=serializers.CharField(max_length=32)
    
    price=serializers.IntegerField()
    
    pub_date=serializers.DateField()
    
    # 想要publish字段显示出版社名字的时候
    
    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
    
    
    
    
    
    # 序列化
    
    class BookViewSet(APIView):
    
    
    
    def get(self,request,*args,**kwargs):
    
    book_list=Book.objects.all()
    
    # 序列化方式1:
    
    # 单个数据对象 model_to_dict(obj),是Django中的一个方法:返回一个字典,key是obj 这个
    
    # 对象的字段名,value是字段对应的值。这种是最快的一种序列化的方式。
    
    # 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))

    注意:

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

    2. rest-framework中对request和response都做了处理, 我们来看一下request在rest-framework中的请求流程及相关处理:

    rest-framework中的request对象不再是Django中原生的HttpRequest对象, 而是rest-framework提供的扩展了HttpRequest类的Request类的对象

    REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典对象保存到Request对象中。

    它和django大致相同,因为它的APIView继承是django的View,但在APiView中重写了dispatch方法

    看到这段代码:

    url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),

    执行PublishViewSet就是APIView的as_view方法

    class APIView(View):

    APIView继承了View,APIView中有as_view方法,所以会执行这个方法,方法中有这么一句代码

    view = super(APIView, cls).as_view(**initkwargs)

    最终还是执行了父类里的as_view方法,所以最终执行结果,得到这么这个view函数。
      下面我们就去源码中看看这个函数的执行顺序:

             def view(request, *args, **kwargs):
    
                self = cls(**initkwargs)
    
                if hasattr(self, 'get') and not hasattr(self, 'head'):
    
                    self.head = self.get
    
                self.request = request
    
                self.args = args
    
                self.kwargs = kwargs
    
                return self.dispatch(request, *args, **kwargs)

    当请求来时,会执行view函数,然后结果调用了dispatch方法,而这里dispatch方法则不是View里的,因为APIView中重写了父类中的dispatch方法,并且是整个rest_framework中最重要的部分,实现了大部分逻辑。  

    def dispatch(self, request, *args, **kwargs):
    
            """
    
            `.dispatch()` is pretty much the same as Django's regular dispatch,
    
            but with extra hooks for startup, finalize, and exception handling.
    
            """
    
            self.args = args
    
            self.kwargs = kwargs
    
            request = self.initialize_request(request, *args, **kwargs)
    
            self.request = request
    
            self.headers = self.default_response_headers  # deprecate?
    
    
    
            try:
    
                self.initial(request, *args, **kwargs)
    
    
    
                # Get the appropriate handler method
    
                if request.method.lower() in self.http_method_names:
    
                    handler = getattr(self, request.method.lower(),
    
                                      self.http_method_not_allowed)
    
                else:
    
                    handler = self.http_method_not_allowed
    
    
    
                response = handler(request, *args, **kwargs)
    
    
    
            except Exception as exc:
    
                response = self.handle_exception(exc)
    
    
    
            self.response = self.finalize_response(request, response, *args, **kwargs)
    
            return self.response


    所以我们可以总结,dispatch是通过view的函数的执行而被调用,那么它返回的结果就是view函数返回的结果,而view函数返回的结果就是as_view()方法返回的结果。也就是通过这样的方式获取到了请求方式并执行。

    3. 使用rest-framework的Response的时候, 服务器端会根据请求的不同请求客户端而发送给客户端不同的数据, 比如使用浏览器访问的时候,会返回一个完整的带数据和格式的页面, 而使用postman进行访问的时候,只返回一个json格式的数据, 当然这两种方式返回的主要数据-json格式的数据都是一样的,只是一个带页面一个不带页面而已

    如在模型中定义一个方法,直接可以在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')

     序列化器的字段校验功能

    # 三种方式
        -字段自己的校验规则(max_length...)
        -validators的校验
            publish = serializers.CharField(max_length=32,validators=[check,])
    
            def check(data):
            if len(data)>10:
                raise ValidationError('最长不能超过10')
            else:
                return data
        -局部和全局钩子
            # 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据
        def validate_title(self, data):
            if data.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return data
        # 全局钩子
        def validate(self, attrs):
            title=attrs.get('title')
            publish=attrs.get('publish')
            if title==publish:
                raise ValidationError('书名不能跟出版社同名')
            else:
                return attrs

    read_only 和 write_only

     read_only    表明该字段仅用于序列化输出,默认False
        write_only    表明该字段仅用于反序列化输入,默认False
        
        
        class BookSerializer(serializers.Serializer):
            # 要序列化哪个字段
            id = serializers.IntegerField(required=False)
            # id=serializers.CharField()
            title = serializers.CharField(max_length=32,min_length=2,read_only=True)
            price = serializers.DecimalField(max_digits=5, decimal_places=2)
            # 序列化的时候看不到
            publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)

    修改,删除接口

    view

       def put(self, request, id):
            # 通过id取到对象
            res = {'code': 100, 'msg': ''}
            try:
                book = models.Book.objects.get(id=id)
                ser = BookSerializer(instance=book, data=request.data)
                ser.is_valid(raise_exception=True)
                ser.save()
                res['msg'] = '修改成功'
                res['result'] = ser.data
    
            except Exception as e:
                res['code'] = 101
                res['msg'] = str(e)
    
            return Response(res)
        def delete(self,request,id):
            response = {'code': 100, 'msg': '删除成功'}
            models.Book.objects.filter(id=id).delete()
            return Response(response)
    View Code

    serializer.py

    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32,min_length=2)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        publish = serializers.CharField(max_length=32)
    
        def create(self, validated_data):
            res=models.Book.objects.create(**validated_data)
            print(res)
            return res
    
        def update(self, book, validated_data):
            book.title=validated_data.get('title')
            book.price=validated_data.get('price')
            book.publish=validated_data.get('publish')
            book.save()
            return book
    View Code

    高级用法之source

    1 修改返回到前端的字段名
        # source=title    字段名就不能再叫title
        name = serializers.CharField(max_length=32,min_length=2,source='title')
    2 如果表模型中有方法
        # 执行表模型中的test方法,并且把返回值赋值给xxx
        xxx=serializers.CharField(source='test')
    3 sourc支持跨表操作
        addr=serializers.CharField(source='publish.addr')
        
    # 希望你们去看以下源码,内部如何实现的
    View Code

    三 rest-framework序列化之ModelSerializer

    • 使用modelSerializer的时候一定要指定序列化数据库中的哪张表

    • 使用rest-framework来操作数据库的时候, 对数据进行增、删、改的时候一定要使用modelSerializer序列化过的

    • fields = "__all__":  该表的所有字段都进行序列化

    • fields=['nid', 'name', 'authors'] :  只序列化列表中的字段

    • exclude=('nid') : 除了元组里边的字段之外该表剩下所有字段进行序列化

    • 在modelSerializer同样可以使用SerializerMethodField

    • 在modelSerializer中可以定义局部钩子和全局钩子对某个字段进行二次校验, 或者加逻辑处理

      • 使用钩子的时候也是固定写法, 局部钩子(def validate_字段名(self, value)) | 全局钩子(def validate(self, value))

      • 在这里要注意加局部钩子的时候的代码缩进, 不要将钩子写到Meta中,写进去之后将无法执行钩子

      • 使用局部钩子的时候,注意要传入value参数, 该参数的值是局部钩子要校验的字段的值

    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

     解释:

    1 原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系
    
    2 使用
        class BookModelSerializer(serializers.ModelSerializer):
            class Meta:
                model=表模型    # 跟哪个表模型建立关系
                fields=[字段,字段] # 序列化的字段,反序列化的字段
                fields='__all__' # 所有字段都序列化,反序列化
                exclude=[字段,字段] # 排除哪些字段(不能跟fields同时使用)
                read_only_fields=['price','publish']  # 序列化显示的字段
                write_only_fields=['title']           # 反序列化需要传入的字段
                extra_kwargs ={'title':{'max_length':32,'write_only':True}}
                depth=1  # 了解,跨表1查询,最多建议写3
            # 重写某些字段
            publish = serializers.CharField(max_length=32,source='publish.name')
            # 局部钩子,全局钩子,跟原来完全一样
    3 新增,修改
        -统统不用重写create和update方法了,在ModelSerializer中重写了create和update
    View Code

    高级用法之SerializerMethodField

    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        name = serializers.CharField(max_length=32,min_length=2,source='title')
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
        publish = serializers.SerializerMethodField()
        def get_publish(self,obj):
            dic={'name':obj.publish.name,'addr':obj.publish.addr}
            return dic
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = '__all__'
        publish = serializers.SerializerMethodField()
        def get_publish(self,obj):
            dic={'name':obj.publish.name,'addr':obj.publish.addr}
            return dic
        
        
        
    ## 第三中方案,使用序列化类的嵌套
    class PublishSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Publish
            # fields = '__all__'
            fields = ['name','addr']
    
    
    class BookModelSerializer(serializers.ModelSerializer):
        publish = PublishSerializer()
    
        class Meta:
            model = models.Book
            fields = '__all__'
    View Code

    四 生成hypermedialink(极少数)

    class BookSerializers(serializers.ModelSerializer):
    
    class Meta:
    
    model = models.Book
    
    fields = "__all__"
    
    # 生成连接,直接查看出版社详情
    
    publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id', lookup_url_kwarg='pkk')
    
    authors=serializers.SerializerMethodField()
    
    def get_authors(self,obj):
    
    ret=obj.authors.all()
    
    ss=AuthorSerializer(ret,many=True)
    
    return ss.data
    
    #--------------
    
    
    
    res=BookSerializers(ret,many=True,context={'request': request})
    
    #--------------
    
    
    
    class Publish(APIView):
    
    def get(self,request,pkk):
    
    print(pkk)
    
    return HttpResponse('ok')
    
    #----路由---
    
    url(r'^publish/(?P<pkk>d+)$', views.Publish.as_view(),name='ttt'),

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

    class BookSerializer1(serializers.Serializer):
    
    title=serializers.CharField(error_messages={'required': '标题不能为空'})
    
    
    
    #这种方式要保存,必须重写create方法

     通过源码查看留的校验字段的钩子函数

    #is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)
    
    # 局部钩子
    
    def validate_title(self, value):
    
    from rest_framework import exceptions
    
    raise exceptions.ValidationError('看你不顺眼')
    
    return value
    
    
    
    # 全局钩子
    
    def validate(self, attrs):
    
    from rest_framework import exceptions
    
    if attrs.get('title')== attrs.get('title2'):
    
    return attrs
    
    else:
    
    raise exceptions.ValidationError('不想等啊')

    序列化组件源码分析

    '''
    
    序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
    
    序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
    
    Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
    
    再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
    
    当参数传过去,判断是方法就加括号执行,是属性就把值取出来
    
    '''

     many = True源码分析,局部全局钩子源码解析

    1 many=True
        -__init__----->一路找到了BaseSerializer---》__new__决定了生成的对象是谁
        
    2 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data)
        -Serializer这个类的:self.run_validation
    def run_validation(self, data=empty):
            value = self.to_internal_value(data)  # 局部字段自己的校验和局部钩子校验
            try:
                self.run_validators(value)
                value = self.validate(value)  # 全局钩子的校验
            except (ValidationError, DjangoValidationError) as exc:
                raise ValidationError(detail=as_serializer_error(exc))
            return value
    View Code

    图书的增删查改resful接口案例:

    视图层:

    class BookSerializers(serializers.ModelSerializer):
    
    class Meta:
    
    model=models.Book
    
    fields='__all__'
    
    
    
    
    
    class BookView(APIView):
    
    
    
    def get(self, request):
    
    book_list = models.Book.objects.all()
    
    bs = BookSerializers(book_list, many=True)
    
    # 序列化数据
    
    
    
    return Response(bs.data)
    
    
    
    def post(self, request):
    
    # 添加一条数据
    
    print(request.data)
    
    
    
    bs=BookSerializers(data=request.data)
    
    if bs.is_valid():
    
    bs.save() # 生成记录
    
    return Response(bs.data)
    
    else:
    
    
    
    return Response(bs.errors)
    
    
    
    class BookDetailView(APIView):
    
    def get(self,request,pk):
    
    book_obj=models.Book.objects.filter(pk=pk).first()
    
    bs=BookSerializers(book_obj,many=False)
    
    return Response(bs.data)
    
    def put(self,request,pk):
    
    book_obj = models.Book.objects.filter(pk=pk).first()
    
    
    
    bs=BookSerializers(data=request.data,instance=book_obj)
    
    if bs.is_valid():
    
    bs.save() # update
    
    return Response(bs.data)
    
    else:
    
    return Response(bs.errors)
    
    def delete(self,request,pk):
    
    models.Book.objects.filter(pk=pk).delete()
    
    
    
    return Response("")
    路由:
    
    
    url(r'^books/$', views.BookView.as_view()),
    
    url(r'^books/(?P<pk>d+)$', views.BookDetailView.as_view()),
     

     drf的请求与响应

    # Request
        -data :前端以post请求提交的数据都在它中
        -FILES :前端提交的文件
        -query_params:就是原来的request.GET
        -重写了 __getattr__
            -使用新的request.method其实取得就是原生request.method(通过反射实现)
            
     # Response
        -from rest_framework.response import Response
        -data:响应的字典
        -status:http响应的状态码
            -drf提供给你了所有的状态码,以及它的意思
            from rest_framework.status import HTTP_201_CREATED
        -template_name:模板名字(一般不动),了解
        -headers:响应头,字典
        -content_type:响应的编码方式,了解
        
        
     # 自己封装一个Response对象
          class CommonResponse:
            def __init__(self):
                self.code=100
                self.msg=''
            @property
            def get_dic(self):
                return self.__dict__
    # 自己封装一个response,继承drf的Response
    
    
    
    
    # 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
        -配置文件方式(全局)
            -如果没有配置,默认有浏览器和json
                -drf有默认配置文件
                from rest_framework.settings import DEFAULTS
                REST_FRAMEWORK = {
                'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
                    'rest_framework.renderers.JSONRenderer',  # json渲染器
                    'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
                )
                }
        -在视图类中配置(局部)
            -粒度更小
            -class BookDetail(APIView):
                renderer_classes=[JSONRenderer,]
    View Code

     https://www.cnblogs.com/liupengfei1123/p/14956539.html

    每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)
  • 相关阅读:
    27. Remove Element
    列表变成字典
    1. Two Sum
    CVPR2019:What and How Well You Performed? A Multitask Learning Approach to Action Quality Assessment
    959. Regions Cut By Slashes
    118. Pascal's Triangle
    loj3117 IOI2017 接线 wiring 题解
    题解 NOI2019 序列
    题解 省选联考2020 组合数问题
    题解 Educational Codeforces Round 90 (Rated for Div. 2) (CF1373)
  • 原文地址:https://www.cnblogs.com/kylin5201314/p/13967128.html
Copyright © 2011-2022 走看看