Django REST framework 简介
在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的。
在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:
-
增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
-
删:判断要删除的数据是否存在 -> 执行数据库删除
-
改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
-
查:查询数据库 -> 将数据序列化并返回
Django REST framework可以帮助我们简化上述两部分的代码编写,大大提高REST API的开发速度。
Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。
通常简称为DRF框架 或 REST framework。
DRF框架是建立在Django框架基础之上,由Tom Christie大牛二次开发的开源项目。
特点
-
提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
-
提供了丰富的类视图、Mixin扩展类,简化视图的编写;
-
丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
-
多种身份认证和权限认证方式的支持;
-
内置了限流系统;
-
直观的 API web 界面;
-
可扩展性,插件丰富。
1. Django RESTFul 协议
1. 服务器端代码
1. 定义类视图
class ***View(View):
def get(self):
def post(self):
2. 视图函数处理步骤
- 接收、验证、处理、响应
3. 配置处理路由规则
4. get或post随便起,但会影响代码可读性和规范性
2. 规范
1. 规则:
- 规定服务器端程序员需要按照哪些标准定义视图、路由规则
2. 作用:
- 增强代码可读性,降低前后端程序员的沟通成本,提高效率
2. RESTFul协议设计方法
1. 域名
应该尽量将API部署在专用域名之下
https://api.example.com
如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。
https://example.org/api/
2. 版本(Versioning)
应该将API的版本号放入URL
http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo
http://www.example.com/app/2.0/foo
3. 路径(Endpoint) 路由规则
路由中的正则表达式必须是名词,建议使用复数,如/books/,/heros/
4. HTTP动词
请求方式 | 数据库数据处理 |
---|---|
GET | 查询 |
POST | 增加 |
PUT | 修改(PUT需要给所有值赋值,PATCH可以修改部分属性) |
DELETE | 删除 |
以下请求方式用的相对较少:
请求方式 | 数据库数据处理 |
---|---|
PATCH | 在服务器更新(更新)资源(客户端提供改变的属性) |
HEAD | 获取资源的元数据 |
OPTIONS | 获取信息,关于资源的哪些属性是客户端可以改变的 |
5. 以查询参数提供过滤条件、分页信息、排序规则
- https://www.baidu.com/python/?a=3&b=5 -->问号后是查询参数
6. 状态码
状态码 | 含义 |
---|---|
200 | 查询成功 |
201 | 新建或修改成功 |
204 | 删除成功 |
3xx | 重定向 |
4xx | 客户端请求有错误 |
5xx | 服务器有错 |
7. 返回值
处理方式 | 响应值 |
---|---|
查询 | {json}或[列表,内部有字典] |
增加 | 新建的对象{} |
修改 | 修改后的对象{} |
删除 | 无 |
8. 所有数据以JSON格式返回
比如 错误信息:
{
error: 'Invalid API key'
}
3. 使用Django开发REST接口
以图书的查询、增加、修改、删除为例
处理 | 请求路径 | 请求方式 | 响应值 | 状态码 |
---|---|---|---|---|
查询(所有) | /books/ | GET | [{},{},…] | 200 |
增加 | /books/ | POST | 新增的数据{} | 201 |
查询(指定主键) | /books/(?P\d+)/ | GET | {} | 200 |
修改 | /books/(?P\d+)/ | PUT | 修改后的对象{} | 201 |
删除 | /books/(?P\d+)/ | DELETE | 无 | 204 |
开发需要两个类视图,一个不包含pk,一个包含pk。
- settings.py 注册子应用
'book.apps.BokConfig',
- book/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^books/$', views.BooksView.as_view()),
url(r'^books/(?P<pk>\d+)/', views.BookView.as_view()),
]
- views.py 视图函数的结构
from django.views import View
class BooksView(View):
def get(self, request):
'''查询所有'''
pass
def post(self, request);
'''新增'''
pass
class BookView(View):
def get(self, request, pk)
'''根据主键查询一个图书对象'''
pass
def put(self, request, pk)
'''修改指定主键的图书对象'''
pass
def delete(self, request, pk)
'''删除指定主键的图书对象'''
pass
- views.py 具体实现:
from django.views import View
from .models import Books
from django.http import JsonResponse
import json
class BooksView(View):
""" 图书类视图 """
def get(self, request):
""" 获取所有图书信息 """
# 接收
# 验证
# 处理
# 1. 查询所有图书对象
book_obj = Books.objects.all()
# 2. 将图书对象转成dict类型
book_info = []
for book in book_obj:
book_info.append({
'id': book.id,
'book_name': book.book_name,
'author': book.author,
'type': book.type,
'published_date': book.published_date,
'date_joined': book.date_joined
})
# 响应
return JsonResponse(book_info, safe=False) # 状态码默认是200,此处无需返回状态码
def post(self, request):
""" 新增图书 """
# 接收
params = json.loads(request.body.decode())
book_name = params.get('book_name')
author = params.get('author')
type = params.get('type')
published_date = params.get('published_date')
date_joined = params.get('date_joined')
# 验证
book_obj = Books.objects.filter(book_name=book_name).first()
if book_obj:
return JsonResponse({'error': 'this book is exist!'})
# 处理
# 1. 创建图书
book = Books.objects.create(book_name=book_name, author=author, type=type, published_date=published_date,date_joined=date_joined)
# 2. 将新创建的图书对象转成dict
book_dict = {
'id': book.id,
'book_name': book.book_name,
'author': book.author,
'type': book.type,
'published_date': book.published_date,
'date_joined': book.date_joined
}
# 响应
return JsonResponse(book_dict, status=201) # 新增成功返回状态码 201
class BookView(View):
""" 图书类视图(含pk) """
def get(self, request, pk):
""" 获取一个图书信息 """
try:
book = Books.objects.get(pk=pk)
except:
return JsonResponse({"error": "数据不存在"})
book_dict = {
'id': book.id,
'book_name': book.book_name,
'author': book.author,
'type': book.type,
'published_date': book.published_date,
'date_joined': book.date_joined
}
return JsonResponse(book_dict)
def put(self, request, pk):
""" 修改一个图书信息 """
# 接收
params = json.loads(request.body.decode())
book_name = params.get('book_name')
author = params.get('author')
type = params.get('type')
published_date = params.get('published_date')
date_joined = params.get('date_joined')
# 验证
try:
book = Books.objects.get(pk=pk)
except:
return JsonResponse({"error": "数据不存在"})
# 更新数据
# 这个方法不行,报【AttributeError: 'Heros' object has no attribute 'update'】错。暂时还不知道为啥,就用了未注释的这种
# book.update(book_name=book_name, author=author, type=type, published_date=published_date,date_joined=date_joined)
book.book_name = book_name
book.author = author
book.type = type
book.published_date = published_date
book.date_joined = date_joined
book.save()
# 将对象转换成字典
book_dict = {
'id': book.id,
'book_name': book.book_name,
'author': book.author,
'type': book.type,
'published_date': book.published_date,
'date_joined': book.date_joined
}
# 响应
return JsonResponse(book_dict, status=201) # 修改成功返回状态码 201
# 处理
def delete(self, request, pk):
""" 删除一个图书 """
# 接收、验证、处理
try:
Books.objects.get(pk=pk).delete()
except:
return JsonResponse({"error": "数据不存在"})
# 响应
return JsonResponse(data={}, status=204) # data= 可写可不写
# 以下是patch方法修改模型类的部分信息,用的不多
def patch(self, request, pk):
""" 使用patch,根据主键pk修改图书部分信息 """
# 接收数据
params = json.loads(request.body.decode())
# book_name = params.get('book_name')
author = params.get('author')
# type = params.get('type')
# published_date = params.get('published_date')
# date_joined = params.get('date_joined')
# 验证
try:
book= Books.objects.get(pk=pk)
except:
return JsonResponse({"error": "该图书不存在"})
# 修改
# book.book_name = book_name
book.author = author # 只改图书的作者
# book.type = type
# book.published_date = published_date
# book.date_joined = date_joined
book.save()
# 将数据对象转成字典
book_dict = {
'id': book.id,
'book_name': book.book_name,
'author': book.author,
'type': book.type,
'published_date': book.published_date,
'date_joined': book.date_joined
}
return JsonResponse(hero_dict, status=201)
如有不足,请多指教!