1. RESTFul API 接口需求及设计
本文以学生信息查询功能为例,采用前后端分离架构,要求后端提供RESTFul 接口。
1.1 本例要求提供如下查询功能:
- 列表查询、单条查询
- 添加学生信息
- 更改学生信息
- 删除学生信息
1.2 数据库student表结构如下:
字段 | 类型 | 长度 | 说明 |
---|---|---|---|
name | string | 30 | 学生姓名 |
no | string | 10 | 学号 |
gender | tiny int | 1 | 0: 男, 1: 女 |
age | int | 4 | 年龄 |
class_name | string | 30 | 班级名称 |
score | int | 4 | 成绩 |
1.3 按REST接口指导原则, RESTFul 风格API 设计如下
在开始之前,推荐阅读 REST接口基本原理
操作 | 请求类型 | 资源请求url | 请求数据 |
---|---|---|---|
列表查询 | GET | http://127.0.0.1:8000/student/ | 无 |
单条查询 | GET | http://127.0.0.1:8000/student/1/ | 无 |
添加记录 | POST | http://127.0.0.1:8000/student/2/ | {‘name’:‘Jack’, ‘no’:‘A001’,…} |
更改记录 | PUT | http://127.0.0.1:8000/student/2/ | {‘name’:‘Jack’, ‘no’:‘B001’,…} |
删除记录 | DELETE | http://127.0.0.1:8000/student/2/ | 无 |
注意,RESTFul风格url 不需要在 url中添加操作动词,如 http://127.0.0.1:8000/student/list/。 当然这样做也可以,只是推荐方式更简洁。
2. 为什么使用Django-rest-framework来开发RESTful API?
Django 是最流行的Python Web开发框架,本身提供了ORM 数据库封装、模板、视图、路由、权限与鉴权, 管理后台等完整的工具链,各种功能开箱即用。 django-rest-framework (简称DRF) 继承了django框架的上述优点,开发与部署不需要第3方库的支持就可以轻松完成数据库CRUD的 REST API开发,并提供完善的鉴权、分级权限控制、测试页面等功能,可以快速地开发出一套高质量的REST API。
其它的框架,如 Flask-Rest,实际应用时,还需要集成数据接口库、鉴权、权限管理等第3方库来完成,测试也需要第3方工具支持,在集成配置,代码质量控制上,难度显然增大了,最终投入成本往往超过django-rest-framework。当然如果你是有经验的Flask开发人员则另当别论。
3. 创建django 项目
3.1 安装 django-rest-framework
创建与激活虚拟环境
python3 -m venv env_rest
cd env_rest
.\script\activate # 激活虚拟环境pip install django
pip install djangorestframework
在linux下激活虚拟环境命令为
source env_test/bin/activate
安装django-rest-framework
pip install django
pip install djangorestframework
3.2 创建django 项目与应用
新建1个项目
django-admin startproject RestTutorial
在RestTutorial 项目下,新建1个app
cd RestTutorial
python manage.py startapp student_rest
3.3 修改全局配置
打开RestTutorial/RestTutorial/settings.py 文件,添加以下配置
INSTALLED_APPS = [...'rest_framework', # 导入DRF库‘student_rest’, # 导入新建app
]# 设置分页器
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 10
}
将语言与时区修改为中国的
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False
3.4 准备model
django默认使用sqlite3 数据库, 你可以将数据库后端 改为mysql, postgreSql 等你熟悉的数据库,细节略过。
**定义Student Model **
打开文件 RestTutorial/student_rest/models.py, 输入以下代码
from django.db import models
from django.urls import reverse# 学生信息model 定义
class Student(models.Model):name = models.CharField(max_length=30,verbose_name="姓名")no = models.CharField(max_length=10,verbose_name="学号") gender = models.IntegerField(max_length=10,verbose_name="性别")age = models.IntegerField(verbose_name="年龄")class_name = models.CharField(max_length=30,verbose_name="班级")score = models.IntegerField(verbose_name="成绩")def __str__(self) -> str:return self.nameclass Meta:db_table = "student"managed = Trueverbose_name = "学生表"verbose_name_plural = verbose_nameunique_together = ['no']
模型定义好以后,需要更新数据库。
python manage.py makemigrations
python manage.py migrate
3.5 将 Student 模型加入到管理后台
为了添加数据方便,可以将新建的model 添加到django管理后台,添加初始数据更加方便
打开 RestTutorial/student_rest/admins.py 文件,添加如下代码
from django.contrib import admin
from .models import *# Register your models here.class StudentAdmin(admin.ModelAdmin):list_display = ['id','name','no','gender','age','class_name','score']list_per_page = 10admin.site.register(Student, StudentAdmin)
3.6 启动项目,添加初始数据
创建1个管理员帐号,并启动项目:
python manage.py createsuperuser
python manage.py runserver 0.0.0.0:8000
如下出现如下信息,就表示运行成功
System check identified 1 issue (0 silenced).
July 06, 2023 - 13:52:06
Django version 3.2.8, using settings 'RestTutorial.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CTRL-BREAK.
打开浏览器,输入 http://127.0.0.1:8000/admin/ ,登录后,进入管理后台。
打开学生表,添加初始数据,
4. DRF编程实现RESTful 接口
DRF 编程很关键的一步是定义Serializer 类,用于将 model 数据序列化。其使用方式与django Form 表单非常相似。
DRF 视图可采用函数式编程,或Class Based View(CBV)视图类的方式编程,并且DRF内置了各种通用视图类来简化编程。
4.1 自定义Serializer 类
新建文件: tutorial/student_rest/serializers.py,, 输入以下代码
from rest_framework import serializers
from .models import Studentclass StudentSerializer(serializers.ModelSerializer):class Meta:model = Studentfields = "__all__"
4.2 用函数式编程实现视图功能
DRF对视图编程,提供了@api_view() 装饰器来实现函数式编程,通常响应仅提供Json字节串,不提供DRF特有的接口测试页面功能。
打开 RestTutorial/student_rest/views.py, 文件,输出以下代码
from django.shortcuts import render
from django.http import JsonResponse, HttpResponse
from rest_framework.parsers import JSONParser
from django.views.decorators.csrf import csrf_exempt
from rest_framework.decorators import api_view
from rest_framework import status
from .models import Student
from .serializers import StudentSerializer# Create your views here.# @csrf_exempt
@api_view(['GET','POST'])
def student_list(request):if request.method == 'GET':# 获取所有数据步骤: 1.获取数据 2.序列化 3.用json格式发送数据qs = Student.objects.all()serilizer = StudentSerializer(qs, many=True)print(serilizer.data)return JsonResponse(serilizer.data, safe=False)elif request.method =='POST':# 新增一条数据的步骤: 1.获取数据 2.反序列化 3.保存至数据库 4.发送结果 data = JSONParser().parse(request)serilizer = StudentSerializer(data=data)if serilizer.is_valid():serilizer.save()return JsonResponse(serilizer.data, status=status.HTTP_201_CREATED)return JsonResponse(serilizer.errors, status=status.HTTP_400_BAD_REQUEST)def student_detail(request,pk):# retrieve, update or delete a row of student model # 读取单条数据try: row = Student.objects.get(pk=pk)except Student.DoesNotExist:return HttpResponse(status=status.HTTP_404_NOT_FOUND)if request.method == 'GET':serializer = StudentSerializer(row)return JsonResponse(serializer.data)elif request.method == 'PUT':input_data = JSONParser().parse(request)serializer = StudentSerializer(row, data=input_data)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data, status=status.HTTP_200_OK)elif request.method == 'DELETE':row.delete()return HttpResponse(status=status.HTTP_204_NO_CONTENT)
打开 tutorial/student_rest/urls.py, 输入
from django.urls import path
from student_rest import views, views_cbvurlpatterns = [path('v1/', views.student_list), # 用于函数式View测试, list, createpath('v1/<int:pk>/', views.student_detail), # 用于函数式View测试, retrieve, update, delete]
url中加入了v1/主要是为了与下一章CBV视图类路由做个区分。
在打开项目的路由本置文件 RestTutorial/RestTutorial/urls.py, 加入一条路由
from django.contrib import admin
from django.urls import path,include
from student_rest import viewsurlpatterns = [path('admin/', admin.site.urls),path('student/', include('student_rest.urls')),
]
4.3 运行并验证
运行项目,
python manage.py runserver 0.0.0.0:8000
前面提到过, 函数式编程不提供测试界面,因此测试接口需要使用第3方工具。
由于浏览器无法发送 post, put, delete消息, 因此建议使用postman 或 curl 等工具来测试
打开postman, 查询所有记录:GET http://127.0.0.1:8000/student/v1/,
测试 添加数据的接口: POST http://127.0.0.1:8000/student/v1/
注意, body 选择raw, json, 手工输入要添加的数据,json格式。
再用list 接口查询,可以看到数据已添加成功。
5. 使用视图类实现REST API
DRF的函数式编程,相对于其它编程语言已经非常简便了。 但前一章可以看出,post, put 实际上还要做校验与保存等工作,delete要做删除等动作,实际应用时可能更多。如果有多个模式,每个类都要写重复语句。为节省这些精力,DRF提供了视图类,混入类来帮助简化编程,同时还提供了测试界面的功能。
5.1 CBV 视图类实现代码
下面我们新建1个文件 RestTutorial/student_rest/views_cbv.py, 输入以下代码
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from .models import Student
from .serializers import StudentSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUserclass StudentList(generics.ListCreateAPIView):queryset = Student.objects.all()serializer_class = StudentSerializerclass StudentDetail(generics.RetrieveUpdateDestroyAPIView):queryset = Student.objects.all()serializer_class = StudentSerializer
非常简洁地就实现了第4章的全部功能。 下面为新的视图类添加路由;
打开 tutorial/student_rest/urls.py, 添加
path("v2/", views_cbv.StudentList.as_view()), # 用于Class-based View测试, list, createpath("v2/<int:pk>/", views_cbv.StudentDetail.as_view()), # 用于Class-based View测试, retrieve, update, delete
5.2 验证
再次运行项目, 这次不需要第3方工具,就可以进行完整测试
打开浏览器, 输入 http://127.0.0.1:8000/student/v2/ , 页面显示如下:
页面最下方提供了添加学习数据的post接口测试功能。
再打开detail view 页面,如http://127.0.0.1:8000/student/v2/6/, 页面如下:
页面下方,是 PUT更改数据的测试接口,上方有delete 按钮,用于测试delete 接口。 接口数据显示也非常友好,也便于前端开发人员阅读。
对于较正式的项目,本人推荐使用django test模块,编写自动化测试脚本,也不需要selenium等第3方测试工具支持。
总结
使用 django-rest-framework 开发基于数据库CRUD的 REST API, 提供完整的内置工具箱,便得整个开发以及测试过程方便快捷,同时,django提供了强大的扩展功能,对于项目的后期扩展、维护也带来了便利。
因此,使用 django-rest-framework 框架进行REST API开发,是中小项目非常不错的选择。
完整项目代码: 点击下载