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 规范

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 接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段

  1. 序列化: 把我们识别的数据转换成指定的格式提供给别人

例如:我们在 Django 中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者 json 数据,提供给别人

  1. 反序列化:把别人提供的数据转换/还原成我们需要的格式

例如:前端 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 浏览页面:

  1. 点击链接 127.0.0.1:8000/stu/students 可以访问获取所有数据的接口,呈现如下页面:
  2. 在页面底下表单部分填写学生信息,可以访问添加新学生的接口,保存学生信息:
  3. 在浏览器中输入网址 127.0.0.1:8000/stu/students/5/,可以访问获取单一学生信息的接口(id为5的学生),呈现如下页面:
  4. 在页面底部表单中填写学生信息,可以访问修改学生的接口
  5. 点击DELETE按钮,可以访问删除学生的接口
posted @ 2020-07-07 20:55  杼柚  阅读(298)  评论(0编辑  收藏  举报