REST framework 介绍
总结一下REST framework:
- 每一个url都代表一种资源
- 客户端和服务器之间,传递这种资源的某种表现层
- 客户端通过HTTP对服务器资源进行操作, 实现"表现层状态转化"
开发模式
在web项目中,一般有两种开发模式:
- 前后端分离.
- 前后端不分离
前后端不分离
前后端不分离,通俗理解为浏览器像服务器发起一个请求,服务器根据请求找到对应的视图,处理逻辑.(CURD), 返回数据,然后视图做相应的填充(展示) 处理({% for %} {% if%}等. 好处呢就是简单,省事儿.适用于小型个人类项目..我之前所在的公司就是采用前后端不分离,前段内哥们天天内个甩锅啊,扯皮啊..唉.无力吐槽...下定决心以后绝对不在搞前后不分离的项目....
前后端分离
前后端分离就比较好理解了,通俗讲就是你跟前段哥们先约定好, 以什么样的方式请求什么样的特定地址返回什么样的特定数据.就完事了,也就是说你把数据给return就没你事了.相比前后端不分离,数据填充你得做,页面的视图判断你得做,循环你得做,... 前后端分离还有一个好处就是具有很好的扩展性并且还大大降低了前后端的耦合性..比如以后扩展app.小程序.. 基本业务逻辑是不用变的.
常用状态码
因为REST framework采用的是前后端分离的思想,我们返回的数据一般都包含了状态码,让前端开发人员用作逻辑判定.所以我们必须了解常用的状态码.
状态码 | 请求方式 | 对应方式 |
200 OK | GET | 成功返回用户的请求数据 |
201 CREATED | POST/PUT/PATCH | 用户新建或者修改数据成功 |
204 NO CONTENT | DELETE | 数据删除成功 |
400 INVALID REQUEST | POST/PUT/PATCH | 用户发出的请求有误 |
401 Unauthorized | [*] | 没有权限(一般账户,密码,令牌有误) |
403 Firbidden | [*] | 有授权,但访问被禁止 |
404 NOT FOUND | [*] | 发出的请求不存在 |
406 Not Acceptable | GET | 请求格式不正确(比如请求json格式,但是只有XML格式) |
410 Gone | GET | 用户请求的资源被删除 |
422 Unprocesable | POST/PUT/PATCH | 创建对象发生错误 |
500 IN..SERV..ERROR | [*] | 服务器错误 |
前端人员根据我们返回的状态码 就可以给出相应的错误提示. 一般来说,返回的信息中将使用error使用键名,错误信息作为键值.ps:口味独特的开发人员除外.
曾经亲眼经历一哥们数据格式: {"nicuole":200, "cuonale":"错误信息"}
返回结果
REST framework 根据用户的不同操作,返回的格式应遵循以下规范:
-
-
- GET /collection 返回资源对象的列表 127.0.0.1/demo 取到的应该是整个接口的所有数据列表
- GET /collection/resource 返回单个资源对象 127.0.0.1/demo/1 取到ID(假设)为1的资源
- POST/collection 返回新生成的资源对象 127.0.0.1/demo 注意这里是post方法
- PUT /collection/resource 返回完整的资源对象 127.0.0.1/1
- PATCH /collection/resource
- DELETE/collection/resource
-
尽可能的用JSON.不到万不得已不要用XML
django开发数据接口
原生的django也可以开发数据接口. 其实数据接口就是返回特定格式的数据,数据里面又包含了特定的内容. 就这么简单.
只不过使用REST framework会简便化我们的很多操作
# 使用视图装饰器来实现. 省略部分代码
from datetime import datetime
class BooksAPIVIew(View): """ 查询所有图书、增加图书
发起get请求. 查询数据库.遍历结果集至一个列表中 ,列表中的元素对应模型对象的数据 """ def get(self, request): """ 查询所有图书 路由:GET /books/ """ queryset = BookInfo.objects.all() book_list = [] for book in queryset: book_list.append({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' })
# JsonResponse 是HttpResponse的子类 他和父类的区别是它的默认Content-Type 被设置为application/json
# safe 这个参数被设置为:False ,那data可以填入任何能被转换为JSON格式的对象,比如list, tuple, set。
return JsonResponse(book_list, safe=False) def post(self, request): """ 新增图书 路由:POST /books/ """ json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str) # 此处详细的校验参数省略 book = BookInfo.objects.create( btitle=book_dict.get('btitle'), bpub_date=datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date() ) return JsonResponse({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }, status=201) class BookAPIView(View): def get(self, request, pk): """ 获取单个图书信息 路由: GET /books/<pk>/ """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) return JsonResponse({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }) def put(self, request, pk): """ 修改图书信息 路由: PUT /books/<pk> """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str) # 此处详细的校验参数省略 book.btitle = book_dict.get('btitle') book.bpub_date = datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date() book.save() return JsonResponse({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }) def delete(self, request, pk): """ 删除图书 路由: DELETE /books/<pk>/ """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) book.delete() return HttpResponse(status=204)
我们在使用 REST 开发API接口时,最最最核心的就是:
- 将数据库数据序列化为前端所需要的格式 返回
- 将前端发送过来的数据反序列化为模型对象,保存到数据库中
安装配置
DRF 是以django扩展方式实现的... 所以 你必须得现有django... 如果没有.... 稍后开篇随便更新安装django与多环境.
看到这里还没关闭页面的小伙伴,我默认为你已经有django环境了,那么请在终端里面敲起你最喜欢的五妹.键入:
pip install djangorestframework
配置
在工程文件夹settings.py的INSTALLED_APPS中添加'rest_framework'
INSTALLED_APPS = [ # 此处省略框架集成 'rest_framework' # 一般我们把别人写的在我们定义的app上面
# 此处省略自定义应用模块 ]
创建序列化器
配置好之后 我们在应用模块新建一个serializers.py 来保存该应用的序列化器.
from rest_framework import serializers
from .models impoer BookInfo
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = '__all__'
model: 指名该序列化器处理的数据字段从模型BookInfo生成
fields: 指名该序列化器包含模型类中的那些字段,'__all__' 指名包含所有字段
编写视图
在应用模块的views.py中创建视图BookInfoViewSet,这是一个视图集合
from rest_framework.viewsets import ModelViewSet from .serializers import BookInfoSerializer from .model import BookInfo
class BookInfoViewsSet(ModelViewSet):
queryset = BookInfo.objects.all() # 指名该视图在查询数据的时候使用的查询集
serializer_class = BookInfoSerializer # 指名该视图在进行序列化或反序列化的时候使用的序列化器
定义路由
在应用模块的urls.py中添加路由信息
from . import views from rest_framework.routers import DefaultRouter urlpatterns = [ ....... ] router = Defaulerouter() # 初始化可以处理视图的路由 router.register = (r"books", views.BookInfoViewSet) # 向路由中注册视图集 urlpatterns += router.urls # 将路由器生成的url追加到django的路由列表
见证奇迹
在浏览器中输入127.0.0.1:/8000 就可以看到framework提供的页面
小节总结
要想使用framework ,
- 保证自己有django
- 安装framework包 pip install restframework
- 注册到settings rest_framework
- 创建序列化器
- 编写视图
- 定义路由
- 运行.