今日内容概要
- 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)