drf快速入门01---REST规范介绍&序列化器的基础使用

一. 基本规范

REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征性状态转移)。 它首次出现在2000年Roy Fielding的博士论文中。

RESTful是一种定义Web API接口的设计风格,尤其适用于前后端分离的应用模式中。

这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。

事实上,我们可以使用任何一个框架都可以实现符合restful规范的API接口。

# 抓包工具:fiddler,charles

# 10条规范
1  数据的安全保障:url链接一般都采用https协议进行传输 注:采用https协议,可以提高数据交互过程中的安全性
2 接口特征表现,一看就知道是个api接口
    - 用api关键字标识接口url:
      - [https://api.baidu.com](https://api.baidu.com/)
      - https://www.baidu.com/api
      注:看到api字眼,就代表该请求url链接是完成前后台数据交互的
3 多数据版本共存
    - 在url链接中标识数据版本
    - https://api.baidu.com/v1
    - https://api.baidu.com/v2
    注:url链接中的v1、v2就是不同数据版本的体现(只有在一种数据资源有多版本情况下)
4 数据即是资源,均使用名词(可复数)
    - 接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
      - https://api.baidu.com/users
      - https://api.baidu.com/books
      - https://api.baidu.com/book

      注:一般提倡用资源的复数形式,在url链接中奖励不要出现操作资源的动词,错误示范:https://api.baidu.com/delete-user
    - 特殊的接口可以出现动词,因为这些接口一般没有一个明确的资源,或是动词就是接口的核心含义

      - https://api.baidu.com/place/search
      - https://api.baidu.com/login
5 资源操作由请求方式决定(method)
    - 操作资源一般都会涉及到增删改查,我们提供请求方式来标识增删改查动作
      - 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:指定返回记录的开始位置
    - 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 响应状态码
   7.1 正常响应
    - 响应状态码2xx
      - 200:常规请求
      - 201:创建成功
   7.2 重定向响应
    - 响应状态码3xx
      - 301:永久重定向
      - 302:暂时重定向
   7.3 客户端异常
    - 响应状态码4xx
      - 403:请求无权限
      - 404:请求路径不存在
      - 405:请求方法不存在
	7.4 服务器异常
    - 响应状态码5xx
      - 500:服务器异常
 8 错误处理,应返回错误信息,error当做key
    {
        error: "无权限操作"
    }
    
 9 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范
    GET /collection:返回资源对象的列表(数组)
    GET /collection/resource:返回单个资源对象
    POST /collection:返回新生成的资源对象
    PUT /collection/resource:返回完整的资源对象
    PATCH /collection/resource:返回完整的资源对象
    DELETE /collection/resource:返回一个空文档
    
 10 需要url请求的资源需要访问资源的请求链接
     # Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么
        {
            "status": 0,
            "msg": "ok",
            "results":[
                {
                    "name":"肯德基(罗餐厅)",
                    "img": "https://image.baidu.com/kfc/001.png"
                }
                ...
                ]
        }

二. 序列化组件介绍

0.模型对象就是querySet
1. 序列化:序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化:完成数据校验功能
4. 序列化哪个字段或者反序列化哪个字段,是自己说的算

三. 基于API+serializer的增删查改

1. 注册app

(如果不使用浏览器进行接口查询,就不用注册,因为这个注册就提供了一个浏览器模板,比如用postman测接口,就不用注册)

INSTALLED_APPS = [
    'rest_framework',
]

 2. models

from django.db import models


# Create your models here.


class Book(models.Model):
    name = models.CharField(verbose_name='书名', max_length=32)
    price = models.DecimalField(verbose_name='价格', decimal_places=2, max_digits=5)
    publish = models.ForeignKey(verbose_name='出版社', to='Publish', on_delete=models.DO_NOTHING)


class Publish(models.Model):
    name = models.CharField(verbose_name='名称', max_length=32)

3.url 

from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('text_1/', views.Text1View.as_view()),
    re_path(r'^text_1/(?P<pk>\d+)/$', views.Text2View.as_view()),
]

view 

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

from . import models
from .sealizer import Text1ViewSerializers, TextModelSerializer


class Text1View(APIView):
    def get(self, request):
        # 群查
        # 1. 获取表模型对象
        book_queryset = models.Book.objects.all()
        # 2. 示例化序列化器对象 固定格式如果是序列化多条一定要填一个many=True
        text_book = Text1ViewSerializers(instance=book_queryset, many=True)
        book_data = {
            "status": 200,
            "msg": "ok",
            "data": text_book.data,
        }
        return Response(data=book_data, status=status.HTTP_200_OK)

    def post(self, request):
        # 新增  request.data--除了GET请求的参数,其他的请求携带数据,都是从request.data这里拿
        text_book = Text1ViewSerializers(data=request.data)
        book_data = {
            "status": 200,
            "msg": "ok",
            "data": "",
        }
        if text_book.is_valid():
            # 注意如果是serializer的话,必须重写create,不然报错
            text_book.save()
            book_data['data'] = text_book.data
            return Response(data=book_data, status=status.HTTP_200_OK)
        book_data['status'] = 400
        book_data['msg'] = text_book.errors
        return Response(data=book_data, status=status.HTTP_400_BAD_REQUEST)


class Text2View(APIView):
    def get(self, request, pk):
        # 单查
        # 1. 获取表模型对象
        book_obj = models.Book.objects.get(pk=pk)
        # 2. 示例化序列化器对象 固定格式
        text_book = Text1ViewSerializers(instance=book_obj)
        book_data = {
            "status": 200,
            "msg": "ok",
            "data": text_book.data,
        }
        return Response(data=book_data, status=status.HTTP_200_OK)

    def patch(self, request, pk):
        # 局部修改  request.data--除了GET请求的参数,其他的请求携带数据,都是从request.data这里拿
        old_book_obj = models.Book.objects.get(pk=pk)
        text_book = Text1ViewSerializers(instance=old_book_obj, data=request.data)
        book_data = {
            "status": 200,
            "msg": "ok",
            "data": "",
        }
        if text_book.is_valid():
            # 注意如果是serializer的话,必须重写update,不然报错
            text_book.save()
            book_data['data'] = text_book.data
            return Response(data=book_data, status=status.HTTP_200_OK)
        book_data['status'] = 400
        book_data['msg'] = text_book.errors
        return Response(data=book_data, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request, pk):
        # 全局修改  request.data--除了GET请求的参数,其他的请求携带数据,都是从request.data这里拿
        old_book_obj = models.Book.objects.get(pk=pk)
        text_book = Text1ViewSerializers(instance=old_book_obj, data=request.data)
        book_data = {
            "status": 200,
            "msg": "ok",
            "data": "",
        }
        if text_book.is_valid():
            # 注意如果是serializer的话,必须重写update,不然报错
            text_book.save()
            book_data['data'] = text_book.data
            return Response(data=book_data, status=status.HTTP_200_OK)
        book_data['status'] = 400
        book_data['msg'] = text_book.errors
        return Response(data=book_data, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        book_data = {
            "status": 200,
            "msg": "ok",
            "data": "",
        }
        models.Book.objects.get(pk=pk).delete()
        return Response(data=book_data, status=status.HTTP_200_OK)

 sealizer.py

from rest_framework import serializers

from .views import models


class Text1ViewSerializers(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        """
        :param validated_data: 校验后的数据
        :return:  必须把创建的对象返回
        """

        book_obj = models.Book.objects.create(
            **{
                'name': validated_data.get('name'),
                'price': float(validated_data.get('price')),
                'publish_id': int(validated_data.get('publish')),
            }
        )
        return book_obj

    def update(self, instance, validated_data):
        """
        :param instance: 老的对象
        :param validated_data: 校验后的数据
        :return:  必须把创建的对象返回
        """
        instance.name = validated_data.get('name')
        instance.price = float(validated_data.get('price'))
        instance.publish_id = int(validated_data.get('publish'))
        # 这个save是orm的
        instance.save()
        return instance

 四. 序列化器属性介绍

read_only	表明该字段仅用于序列化输出,默认False,如果设置成True,postman中可以看到该字段,修改时,不需要传该字段
write_only	表明该字段仅用于反序列化输入,默认False,如果设置成True,postman中看不到该字段,修改时,该字段需要传

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

五. 反序列化校验三种方法

1. 局部钩子

class BookSerializer(serializers.Serializer):
    name=serializers.CharField(max_length=16,min_length=4)
    price=serializers.CharField()
    publish=serializers.CharField()
    def validate_price(self, data):   # validate_字段名  接收一个参数
        # data就是price
        #如果价格小于10,就校验不通过
        if float(data)>10:
            return data
        else:
            #校验失败,抛异常
            raise serializers.ValidationError('价格太低')

2. 全局钩子

class BookSerializer(serializers.Serializer):
    name=serializers.CharField(max_length=16,min_length=4)
    price=serializers.CharField()
    publish=serializers.CharField()

    def validate(self, validate_data):   # 全局钩子
        # print(validate_data)  所有校验完的数据,全局钩子是最后一道管卡
        name=validate_data.get('name')
        publish=validate_data.get('publish')
        if name== publish:
            raise ValidationError('xxxx')
        else:
            return validate_data

3. 函数校验

def check_name(data):
    if data.startswith('sb'):
        raise ValidationError('name不能以sb开头')
    else:
        return data


class BookSerializer(serializers.Serializer):
    name=serializers.CharField(max_length=16, min_length=4, validators=[check_author,])
    price=serializers.CharField()
    publish=serializers.CharField()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑猪去兜风z1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值