今日内容概要
- restful规范
- 序列化与反序列化
- 基于django原生编写5个接口
- drf介绍和快速使用
- cbv源码分析
今日内容详细
restful规范
概念
	REST全称是Representational State Transfer, 中文意思是表述:表征性状态转移, 它首次出现在2000年Roy Fielding的博士论文中
RESTful是一种定义web API接口的设计风格 尤其适用于前后端分离的应用模式中
十个规范
	1.数据的安全保障
		通常使用HTTPS(HTTP+ssl/tsl)协议 采用HTTPS协议 可以提高数据交互过程中的安全性
	2.接口中带api标识
		如: https://api.baidu.com/books
		   https://www.baidu.com/api/books
	3.多版本共存 路径中带版本信息
		如: https://api.baidu.com/v1/login
			https://www.baidu.com/api/v2/login
	4.数据即是资源 均使用名词 尽量不要使用动词(最核心的)
		接口一般都是完成前后端数据的交互 交互的数据我们称之为资源
		接口形式如下:
			https://api.baidu.com/users
			https://api.baidu.com/books		# 取所有的书 不使用动词get等动词命名
		特殊的接口可以出现动词 因为这些接口没有一个明确的资源 或是动词就是接口的核心含义
			https://api.baidu.com/login
	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			delete请求:删除主键为1的书
		路由都相同 但是根据请求方式的不同执行不同的操作
	6.在请求地址中带过滤条件
		https://api.baidu.com/books?name=红&price=99
	7.响应中状态码	有两套
		HTTP响应状态码:
			1xx		请求正在处理
			2xx		成功响应
			3xx		重定向
			4xx		客户端错误
			5xx		服务端错误
		公司内部规定的响应状态码 放在响应体中 如 10000 10001 10002 ...
	8.返回数据中带错误信息
		{code:0, msg:"error/用户名错误"}
	9.返回的结果应该符合以下规范--->>>有些公司不遵循这个
		GET获取所有数据: 返回资源对象的列表(数组) # [{name: 红楼梦, price: 99},...]
		GET获取单个对象: 返回单个资源对象 # {name: 红楼梦, price: 99}
		POST新增对象: 返回新生成的资源对象 # {name: 西游记, price: 88}
		PUT修改对象: 返回完整的资源对象 # {name: 西游记, price: 100}
		DELETE删除: 返回一个空对象
	10.响应数据中带连接
序列化与反序列化
	api接口开发 最核心最常见的一个过程就是序列化 所谓序列化就是把数据转换格式 序列化可以分两个阶段
1.序列化 把我们识别的数据转换成指定的格式提供给别人
	字典 列表 ----> json格式存到文件中了
	例如 我们在django中获取到的数据默认是模型对象 但是模型对象数据无法直接提供给前端或别的平台使用 所以我们需要把数据进行序列化 变成字符串或者json数据 提供给别人--read
2.反序列化 把别提供的数据转换 还原成我们需要的格式
	例如 前端js提供过来的json数据 对于python而言就是字符串 我们需要进行反序列化成模型类对象 这样我们才能把数据保存到数据库中--write
基于django原生编写5个接口
class BooksView(View):
    def get(self, request, id=None):
        if id:
            book = Books.objects.filter(pk=id).first()
            return JsonResponse({'name': book.name, 'price': book.price, 'publish': book.publish})
        books = Books.objects.all()
        # book_list = []
        # for book in books:
        #     book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        book_list = [{'name': book.name, 'price': book.price, 'publish': book.publish} for book in books]
        print(book_list)
        return JsonResponse(book_list, safe=False)
    def post(self, request):
        if request.POST:
            # name, price, publish = request.POST.values()
            # book = Books.objects.create(name=name, price=price, publish=publish)
            book = Books.objects.create(**dict(request.POST.items()))
            return JsonResponse({'name': book.name, 'price': book.price, 'publish': book.publish})
        book_dict = json.loads(request.body)
        book = Books.objects.create(**book_dict)
        return JsonResponse({'name': book.name, 'price': book.price, 'publish': book.publish})
    def put(self, request, id):
        new = json.loads(request.body)
        book = Books.objects.filter(pk=id)
        book.update(**new)
        book = book.first()
        return JsonResponse({'name': book.name, 'price': book.price, 'publish': book.publish})
    def delete(self, request, id):
        Books.objects.filter(pk=id).delete()
        return JsonResponse({})
drf介绍和快速使用
djangorestframework简称drf 用于帮助我们快速的实现符合restful规范的接口
drf最新支持到django3.x 不支持2.x 如果使用的django2.x 那么安装drf的时候会自动将django更新到最新版
drf安装
	pip3 install djangorestframework -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com/simple/
使用drf编写5个接口
# views中
from .serializer import BookSerializer
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
# serializer中  需要自己在app中新建一个py文件并且取名为serializer
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
# urls中
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns += router.urls
CBV源码分析
路由中写的 path('api/v1/books/', views.BooksView.as_view()),
由于as_view有括号 那么优先执行这个函数 我们自身写的BookView继承了View类 自身又没有as_view函数 那么就会执行父类中的as_view函数 查看源码发先这是一个绑定给类的方法 并且返回了一个view函数的内存地址
当请求过来了 并且匹配成功 就会执行view函数 最终又会返回dispatch函数执行的结果
    def view(request, *args, **kwargs):
        # 产生一个视图类的对象并赋值给self
        self = cls(**initkwargs)
        return self.dispatch(request, *args, **kwargs)
查看该函数源码
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    def dispatch(self, request, *args, **kwargs):
        # 将当前请求方式转小写 判断是否在对应列表中
        if request.method.lower() in self.http_method_names:
            # 如果在 那么利用反射去自身中取对应方法 并赋值给handler
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        # 将取到的方法执行并返回 实现什么请求执行对应请求的方法
        return handler(request, *args, **kwargs)