restful规范、序列化组件

一、restful规范

1、Representional State Transfer:表征性状态转移
2、Web API 接口的设计风格,尤其适用于前后端分离的项目
3、与语言、平台无关,任何框架都可以写出restful规范的api接口
4、规范:10条
-1、数据的安全保障:Url链接一版都采用https协议进行传输
-2、接口特征表现:用api关键字标识接口url

https://www.baidu.com/api
#看到api字眼,就代表该请求url链接是完成前后台数据交互的

-3、多版本共存:url链接中标识接口版本:
https : http ssl 传输协议
https://api.baidu.com/v1/books/
https://api.baidu.com/v2/books/
-4、数据即是资源,均使用名词(可复数)
-接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
-一般提倡用资源的复数形式,不要使用动词

例:查询所有图书
https://api.baidu.com/books/  # 正确
https://api.baidu.com/get_all_books/ # 错误示范
https://api.baidu.com/delete-user    # 错误的示范
https://api.baidu.com/user   # 删除用户的示例:疑问:到底是删还是查?

-5、资源操作由请求方式决定:

https://api.baidu.com/books       # get请求:获取所有书
https://api.baidu.com/books/1     # get请求:获取主键为1的书
https://api.baidu.com/books       # post请求:新增一本书书
https://api.baidu.com/books/1     # put请求:整体修改主键为1的书
https://api.baidu.com/books/1     # patch请求:局部修改主键为1的书
https://api.baidu.com/books/1     # delete请求:删除主键为1的书

-6、过滤:通过在url上传参的形式传递搜索条件

https://api.example.com/v1/zoos?limit=10      # 指定返回记录的数量
https://api.example.com/v1/zoos?offset=10&limit=3   # 指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100   # 指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc   # 指定返回结果按照哪个属性排序,以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1   # 指定筛选条件

-7、响应状态码
返回数据中带状态码
{'code' : 100}

#正常响应
响应状态码2xx
200:常规请求
201:创建成功
#重定向响应
301:永久重定向
302:暂时重定向
#客户端异常
403:请求无权限
404:请求路径不存在
405:请求方式不存在
#服务器异常
500:服务器异常

-8、返回结果中带错误信息
{'code' : 100 , 'msg' : '因为xx原因失败'}
-9、返回结果,该符合以下规范

GET /collection    # 返回资源对象的列表(数组)
 GET /collection/resource   #返回单个资源对象(字典)
POST /collection  # 返回新生成的资源对象(新增后的对象字典)
PUT /collection/resource   # 返回完整的资源对象(修改后的对象字典)
PATCH /collection/resource   # 返回完整的资源对象(修改后的对象字典)
DELETE /collection/resource   # 返回一个空文档()

-10、返回的数据中带链接地址

查询id为1的图书接口,返回结果示例
{'code':100,
'msg':'成功,
'result':
        {'title':'金瓶梅',
         'price':'12.3',
         'publish':'https://127.0.0.1/api/v1/publish/3'}
}

二、APIView源码分析

1、APIview的as_view
    -内部还是执行了View的闭包函数view
    -禁用掉了csrf
    -一切皆对象,函数也是对象  函数地址.name=lqz
image.png
2、原生View类中过的as_view中的闭包函数view
    -本质执行了self.dispatch(request, *args, **kwargs),执行的是APIView的dispatch
image.png
3、APIView的dispatch
def dispatch(self, request, *args, **kwargs):
        # DRF的Request类的对象,内部有request._request,是原生request
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

        try:
            self.initial(request, *args, **kwargs)
            '''
            #认证,权限,频率
            self.perform_authentication(request)
            self.check_permissions(request)
            self.check_throttles(request)
            '''
            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)
        # 把视图函数(类)返回的response,又包装了一下
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
image.png

image.png

三、Request类的分析

-request._request:原生request
    -request.data    : post请求提交的数据(urlencoded,json,formdata)
    -request.user    :不是原生的user了
    -request.query_params :原生的request.GET,为了遵循restful规范的第六条,查询条件
    -requset.FILES   :新的
    -重写了__getattr__,新的request.原来所有的属性和方法,都能直接拿到
        def __getattr__(self, attr):
            return getattr(self._request, attr)

四、序列化组件介绍

1、序列化:序列化器会把模型对象转换成字典经过response以后变成json字符串
例:Book---序列化器---转成字典----通过drf:Response----json格式字符串----传给前端
2、反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
例:json格式数据----drf:Request---转成字典----序列化器----Book
反序列化可以完成数据校验功能

五、序列化组件简单使用

1、写一个序列化类继承serializers.Serializer
2、在类中写要序列化的字段
3、在视图类中,实例化得到一个序列化类的对象,把要序列化的数据传入
ser=BookSerializer(instance=res,many=True)
4、得到字典
ser.data就是序列化后的字典

###代码实现
#models.py
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.CharField(max_length=32)
#serializer.pyfrom rest_framework import serializers
class BookSerializer(serializers.Serializer):
    # 要序列化哪个字段
id=serializers.IntegerField()
    # id=serializers.CharField()   title=serializers.CharField(max_length=32)   price=serializers.DecimalField(max_digits=5, decimal_places=2)
publish=serializers.CharField(max_length=32)
#views.py
from app01 import models
from app01.serializer import BookSerializer
class Book(APIView):
    def get(self,request,*args,**kwargs):

        res=models.Book.objects.all()
        # 借助序列化器
        # 如果是多条,就是many=True
        # 如果是单个对象,就不写
        ser=BookSerializer(instance=res,many=True)
        # 通过序列化器得到的字典
        # ser.data
        print(ser.data)
        return Response(ser.data)
#urls.py
path('books/', views.Book.as_view()),

六、序列化类字段类型和字段参数

1、字段类型
-IntegerField
-CharField
-DecimalField
-DateTimeField
2、常用字段参数
选项参数:max_length 最长长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最小值
min_value 最大值
通用参数:

#重点
read_only    # 表明该字段仅用于序列化输出,默认False
write_only   # 表明该字段仅用于反序列化输入,默认False
#掌握
required   # 表明该字段在反序列化时必须输入,默认True
default   #  反序列化时使用的默认值
allow_null   # 表明该字段是否允许传入None,默认False
#了解
validators   # 该字段使用的验证器、
error_messages   # 包含错误编号与错误信息的字典

七、序列化器的保存功能

#视图类
class Book(APIView):
    # def get(self,request,*args,**kwargs):
    #     res = models.Book.objects.all()
    #     ser = BookSerializer(instance=res,many=True)
    #     print(type(ser))
    #     print(ser.data)
    #     return Response(ser.data)
    def post(self,request,*args,**kwargs):
        print(request.data)
        ser = BookSerializer(data=request.data)
        print(ser)
        if ser.is_valid():
            ser.save()   # 保存在数据库中
            return Response(ser.data)
        else:
            return Response(ser.errors)  # 没有校验通过的错误信息
#序列化类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models
def check(data):
    if len(data) > 10:
        raise ValidationError('长度不应长于10位')
    else:
        return data
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,validators=[check,])
#重写create方法,指定表名
    def create(self, validated_data):
        res = models.Book.objects.create(**validated_data)
        print(res)
        return res

八、序列化器的字段校验功能

#三种校验方式
###1、字段自己的校验规则(max_length...)
###2、validators的校验
publish = serializers.CharField(max_length=32,validators=[check,])
def check(data):
    if len(data) > 10:
        raise ValidationError('长度不应长于10位')
    else:
        return data
###3、局部钩子和全局钩子
#局部钩子validate_字段名,需要带一个data参数,data就是该字段的数据
 def validate_title(self,data):
        if data.startswith('sb'):
            raise ValidationError('不能以sb开头')
        else:
            return data
#全局钩子,attrs表示所有数据
    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)
    title = serializers.CharField(max_length=32,min_length=2,read_only=True)  # 可以不写,数据库设置null = True,反序列化时可以显示为空
    price = serializers.DecimalField(max_digits=5,decimal_places=2)
    publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)  # 序列化的时候看不到

十、修改、删除接口

#视图类
    def put(self,request,id,*args,**kwargs):
        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):
        res = {'code':100,"msg":'删除成功'}
        models.Book.objects.filter(id = id).delete()
        return Response(res)
#序列化类
#重写了update的方法
    def update(self, instance, validated_data):
        instance.title = validated_data.get('title')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance

十一、高级用法之source

1、修改返回到前端的字段名

name = serializers.CharField(max_length=32,min_length=2,source='title')
#title为models类中的字段

2、如果表模型中有方法

#表模型中的方法
    def test(self):
        return self.title + str(self.price)
#执行表模型中的test方法,并把返回值赋值给xxx
xxx = serializers.CharField(source='test')

3、source支持跨表操作

例:查询publish中的名字以及地址
#models.py
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5,decimal_places=2)
    publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)

    def test(self):
        return self.title + str(self.price)
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    def __str__(self):
        return self.name
#serializer.py
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.CharField(max_length=32,validators=[check,])
    xxx = serializers.CharField(source='test')
    publish_name = serializers.CharField(source='publish.name')
    publish_addr = serializers.CharField(source='publish.addr')
#views.py
class Book(APIView):
    def get(self,request,*args,**kwargs):
        res = models.Book.objects.all()
        ser = BookSerializer(instance=res,many=True)
        print(type(ser))
        print(ser.data)
        return Response(ser.data)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258