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.(清楚优于含糊)
  • 相关阅读:
    第十三课:js操作节点的创建
    matlab 绘制条形图
    Pearson(皮尔逊)相关系数及MATLAB实现
    Spearman Rank(斯皮尔曼等级)相关系数及MATLAB实现
    A Regularized Competition Model for Question Diffi culty Estimation in Community Question Answering Services-20160520
    Competition-based User Expertise Score Estimation-20160520
    We Know What @You #Tag: Does the Dual Role Affect Hashtag Adoption-20160520
    matlab 画图数据导入
    Who Says What to Whom on Twitter-www2011-20160512
    The Lifecycle and Cascade of WeChat Social Messaging Groups-www2016-20160512
  • 原文地址:https://www.cnblogs.com/kylin5201314/p/13967128.html
Copyright © 2011-2022 走看看