DRF 入门规范
一、Web 应用模式
在开发 Web应用中,有两种应用模式:
1. 前后端不分离
前后端不分离:客户端看到的内容和所有界面效果都是由服务端提供出来的
在这种情况下,前端页面会出现很多涉及到服务端的模板语法
2. 前后端分离
前后端分离:把前端的界面效果(html、css、js 分离到另一个项目中,Python 服务端只需要返回数据即可)
前端形成一个独立的网站,服务端构成一个独立的网站
Djang 框架一般都是做 Web 网站,如果可以利用 Django框架实现前后端分离,则 Django 就可以完成地铁站的运营调度系统,路由的终端系统,如 pos 机的服务端系统、游戏的服务端后台以及软件的服务端后台等
二、API 接口
为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少双方之间的合作成本
通过网络,规定前后台信息交互规则的 url 链接,也就是前后台信息交互的媒介
Web API 接口和一般的 url 链接还是有区别的,Web API 接口简单概括有以下四个特点
- url:长得像返回的数据的 url 链接(https://api.map.baidu.com/place/v2/search)
- 请求方式:get、post、put、patch、delete(采用 get 方式请求上方接口)
- 请求参数:json 或 xml 格式的 key-value 类型数据
- ak:6E823f587c95f0148c19993539b99295
- region:上海
- query:老男孩教育
- output:json/xml
- 响应结果:json 或 xml 格式的数据
<?xml version="1.0" encoding="utf-8" ?>
<PlaceSearchResponse>
<status>0</status>
<message>ok</message>
<results>
<result>
<name>老男孩教育(上海校区)</name>
<location>
<lat>31.157594</lat>
<lng>121.609077</lng>
</location>
<address>上海浦东新区康桥东路298号张江创智良仓三楼</address>
<province>上海市</province>
<city>上海市</city>
<area>浦东新区</area>
<telephone>17612156221,18917595753</telephone>
<detail>1</detail>
<uid>72b2d8c8ad2b3c1017b54bb1</uid>
</result>
<result>
<name>老男孩教育</name>
<location>
<lat>31.150239</lat>
<lng>121.632452</lng>
</location>
<address>上海市浦东新区川周公路与申江南路交叉路口往西南约100米(上海康桥凯莱酒店)</address>
<province>上海市</province>
<city>上海市</city>
<area>浦东新区</area>
<detail>1</detail>
<uid>b4e936c86812620dad045791</uid>
</result>
<result>
<name>老男孩培训</name>
<location>
<lat>31.206036</lat>
<lng>121.269699</lng>
</location>
<address>上海市青浦区华徐公路999号e通商务楼b座</address>
<province>上海市</province>
<city>上海市</city>
<area>青浦区</area>
<detail>1</detail>
<uid>ab17b7a9c7bc82a9cb213d90</uid>
</result>
</results>
</PlaceSearchResponse>
{
"status":0,
"message":"ok",
"results":[
{
"name":"老男孩教育(上海校区)",
"location":{
"lat":31.157594,
"lng":121.609077
},
"address":"上海浦东新区康桥东路298号张江创智良仓三楼",
"province":"上海市",
"city":"上海市",
"area":"浦东新区",
"telephone":"17612156221,18917595753",
"detail":1,
"uid":"72b2d8c8ad2b3c1017b54bb1"
},
{
"name":"老男孩教育",
"location":{
"lat":31.150239,
"lng":121.632452
},
"address":"上海市浦东新区川周公路与申江南路交叉路口往西南约100米(上海康桥凯莱酒店)",
"province":"上海市",
"city":"上海市",
"area":"浦东新区",
"detail":1,
"uid":"b4e936c86812620dad045791"
},
{
"name":"老男孩培训",
"location":{
"lat":31.206036,
"lng":121.269699
},
"address":"上海市青浦区华徐公路999号e通商务楼b座",
"province":"上海市",
"city":"上海市",
"area":"青浦区",
"detail":1,
"uid":"ab17b7a9c7bc82a9cb213d90"
}
]
}
三、接口测试工具(Postman)
Postman 是一款接口测试工具,是一款免费的可视化软件,同时支持各种操作系统凭条,是测试 接口的首要工具
Postman 下载地址:https://www.postman.com/downloads/
四、RESTful API 规范
REST 全称是 Representational State Transfer,中文意思是表述(编者注:通常译为表征性状态转移)。它首次出现在2000年Roy Fielding 的博士论文中
RESTful 是一种定义 Web API 接口的设计风格,尤其适用于前后端分离的应用模式中
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问 URL 路径就表示这种操作的数据资源
事实上,我们可以使用任何一个框架都可以实现 RESTful 规范的 API 接口
1. 数据的安全保障
url 链接一般都采用 https 协议进行传输
注:采用 https 协议,可以提高数据交互过程中的安全性
2. 接口特征表现
用 api 关键字标识接口 url:https://api.map.baidu.com/place/v2/search
注:看到 api 字眼,就代表该请求 url 链接是完成前后端数据交互的
3. 多数据版本共存
在 url 链接中标识数据版本
注:url链接中的 v1、v2 就是不同数据版本的体现(只有在一种数据资源有多版本情况下)
4. 数据即是资源,均使用名词(可复数)
接口一般都是完成前后台数据的交互,交互的数据我们称之为资源
注:一般提倡用资源的复数形式,在url链接中奖励不要出现操作资源的动词,错误示范:https://api.baidu.com/delete-user
5. 资源操作由请求方式决定
操作资源一般都会涉及增删查改,我们提供请求方式来标识增删查改动作
例如:http://api.baidu.com/students
请求方法 | 请求地址 | 后端操作 |
---|---|---|
GET | /students | 获取所有学生 |
POST | /students | 增加学生 |
GET | /students/ |
获取主键为 pk 的学生 |
PUT | /students/ |
修改主键为 pk 的学生 |
DELETE | /students/ |
删除主键为 pk 的学生 |
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. 响应状态码
# 正常响应
响应状态码:2XX
- 200:请求成功
- 201:创建成功
# 重定向响应
响应状态码:3XX
- 301:永久重定向
- 302:暂时重定向
# 客户端异常
响应状态码:4XX
- 403:请求无权限
- 404:请求路径不存在
- 405:请求方法不存在
# 服务器异常
响应状态码: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"
}
...
]
}
比较好的接口返回
响应数据要有状态码、状态信息以及数据本身
{
"status": 0,
"msg": "ok",
"results":[
{
"name":"肯德基(罗餐厅)",
"location":{
"lat":31.415354,
"lng":121.357339
},
"address":"月罗路2380号",
"province":"上海市",
"city":"上海市",
"area":"宝山区",
"street_id":"339ed41ae1d6dc320a5cb37c",
"telephone":"(021)56761006",
"detail":1,
"uid":"339ed41ae1d6dc320a5cb37c"
}
...
]
}
四、序列化
api 接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段
- 序列化: 把我们识别的数据转换成指定的格式提供给别人
例如:我们在 Django 中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者 json 数据,提供给别人
- 反序列化:把别人提供的数据转换/还原成我们需要的格式
例如:前端 js 提供过来的 json 数据,对于 Python 而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中
五、Django Rest_Framework
核心思想: 缩减编写 api 接口的代码
Django REST framework 是一个建立在 Django 基础之上的 Web 应用开发框架,本质上就是一个内置在 Django 里面的子应用,可以快速的开发 REST API 接口应用
在 REST framework 中,提供了序列化器 Serialzier 的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework 还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework 提供了一个 API 的 Web 可视化界面来方便查看测试接口
官方文档:https://www.django-rest-framework.org/
github: https://github.com/encode/django-rest-framework/tree/master
特点
- 提供了 定义序列化器 Serializer 的方法,可以快速根据 Django ORM 或者其他库自动序列化/反序列化
- 提供了丰富的类视图,Mixin 扩展类,简化视图的编写
- 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API ,满足各种需要
- 多种身份认证和权限认证方式的支持
- 内置了限流系统
- 直观的 API Web 界面(方便我们调试开发 API 接口)
- 可扩展性,插件丰富
六、环境安装与配置
DRF 需要以下依赖:
- Python(2.7,3.2以上)
- Django (1.10,1.11,2.0以上)
DRF 是以 Django 扩展应用的方式提供的,所以我们可以直接利用已有的 Django 环境而无需重新创建(若没有 Django 环境,需要先创建环境安装 Django)
1. 安装 DRF
前提是已经安装了Django,建议安装在虚拟环境
mkvirtualenv drfdemo -p python # 创建 drfdemo 文件夹
pip install django==1.11.11
pip install djangorestframework
pip install pymysql
创建 Django 项目
cd ~/Desktop
django-admin startproject drfdemo
使用 PyCharm 打开项目,设置虚拟环境的解析器,并修改 manage.py 中的后缀参数
2. 添加 rest_framework 应用
在 settings.py 的 INSTALLED_APPS 中添加 rest_framework
INSTALLED_APPS = [
...
'rest_framework',
]
接下来就可以使用DRF提供的功能进行 api 接口开发了。在项目中如果使用 rest_framework 框架实现API接口,主要有以下三个步骤
- 将请求的数据(如JSON格式)转换为模型类对象
- 操作数据库
- 将模型类对象转换为响应的数据(如JSON格式)
3. 体验 DRF 完全简写代码的过程
1) 创建模型操作类
from django.db import models
# Create your models here.
class Student(models.Model):
# 表字段声明
# 字段名=models.数据类型(字段约束)
name = models.CharField(null=False, max_length=32, verbose_name="姓名")
sex = models.BooleanField(default=True, verbose_name="性别")
age = models.IntegerField(verbose_name="年龄")
class_num = models.CharField(max_length=5, verbose_name="班级编号")
description = models.TextField(max_length=1000, verbose_name="个性签名")
# 表信息
class Meta:
# 设置表名
db_table="tb_students"
verbose_name="学生"
verbose_name_plural=verbose_name
# 模型的操作方法
def __str__(self):
return self.name
为了方便测试需要自己创建一个数据库
create database students charset='utf-8';
执行数据库迁移命令
把 books 子应用添加到 INSTALL_APPS 中,是要放在 rest_framework
下面去
初始化数据库连接(当然要使用 MySQL 还需要注意在 settings.py 中设置)
# 安装 pymysql
pip install pymysql
settings.py 配置文件中设置 MySQL 的账号密码
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'drfdemo',
'USER': 'root',
'PASSWORD': '123',
'HOST': '127.0.0.1',
'PORT': 3306,
'CHARSET': 'utf8'
}
}
主引用 __init__.py
设置使用 pymysql 作为数据库驱动
import pymysql
pymysql.install_as_MySQLdb()
终端下,执行数据迁移
python manage.py makemigrations
python manage.py migrate
2) 创建序列化器
例如:在 Django 项目中创建学生子应用
python manage.py startapp students
在 students 应用目录中新建 serializers.py 用于保存该应用的序列化器
创建一个 StudentModelSerializer 用于序列化和反序列化
# 创建序列化器,回头会在视图中被调用
from rest_framework import serializers
from .models import Student
class StudentModelSerializer(serializers.ModelSerializer):
class Mera:
model = Student
fields = '__all__'
- model:指明该序列化器处理的数据字段从模型类
BookInfo
参考生成 - fields:指明该序列化器包含模型类中的哪些字段,
__all__
指明包含所有字段
3) 编写视图
在 students
应用的 view.py
中创建视图 StudentViewSet
,这是一个视图集合
from rest_framework.viewsets import ModelViewSet
from .models import Student
from .serializers import StudentModelSerializer
# Create your views here.
class StudentViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
- query_set:指明该视图集在查询数据时使用的查询集
- serializer_class:指明该视图在进行序列化或反序列时使用的序列化器
4) 定义路由
在 students
应用的 urls.py
中定义路由信息
from . import views
from rest_framework.routers import DefaultRouter
# 路由列表
urlpatterns = []
router = DefaultRouter() # 可以处理视图的路由器
router.register('students', views.StudentViewSet) # 向路由器中注册视图集
urlpatterns += router.urls # 将路由器中的所以路由信息追到到django的路由列表中
最后把 students
子应用中的路由文件加载到总路由文件中
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path("student/",include("students.urls")),
]
5) 运行测试
运行当前程序(与运行 Django 一样)
python manage.py runserver
在浏览器中输入网址 127.0.0.1:8000
,可以看到 DRF 提供的 API Web 浏览页面:
- 点击链接
127.0.0.1:8000/stu/students
可以访问获取所有数据的接口,呈现如下页面: - 在页面底下表单部分填写学生信息,可以访问添加新学生的接口,保存学生信息:
- 在浏览器中输入网址
127.0.0.1:8000/stu/students/5/
,可以访问获取单一学生信息的接口(id为5的学生),呈现如下页面: - 在页面底部表单中填写学生信息,可以访问修改学生的接口:
- 点击DELETE按钮,可以访问删除学生的接口: