手把手教你用Django实现RESTful接口
1 阅读说明
- 本篇阅读对象定位为具有一定Django使用经验的开发人员;
- 本篇需要10min左右阅读。
2 Rest Api架构
随着前后端分离,RESTful风格接口正越来越受到欢迎。 本篇文章介绍如何使用Django框架实现RESTFful接口。
各个组件说明:
- Url Patterns, 将请求路由到具体处理的视图;
- View,处理HTTP请求并返回HTTP Response;
- Serializer,序列化/反序列化模型数据;
- Models,模型,负责与数据库相关操作;
与常用的的Django应用相比,Restful风格接口仅仅是多使用了Serializer组件。
3 一步一步实现Django Restful接口
首先我们设置Django项目。接着我们创建Rest Api应用,将该应用和Django Rest Framework一同加入到项目中。再次我们定义数据模型,执行数据库迁移。然后我们编写API视图,定义路由处理所有CRUD操作。最后我们使用Postman测试创建的API。
3.1 依赖的Python包
- Python 3.7
- Django 2.1.15
- Django Rest Framework 3.11.0
- Django-cors-headers 3.2.1
3.2 项目结构
3.3 安装Django REST framework
Django没有内置的插件支持建立RESTful风格的接口,我们需要安装第三方插件来完成任务。
pip install djangorestframework
3.3 创建新Django项目
使用django-admin工具创建新项目。
django-admin startproject DjangoRestApi
打开settings.py文件,将Django REST framework添加到INSTALLED_APPS配置中。
INSTALLED_APPS = [
'rest_framework',
]
3.4 新建API应用
cd DjangoRestApi
python manage.py startapp tutorials
这里应用名命名为tutorials。打开tutorials/apps.py,你可以看到新应用的名称,把名称添加到INSTALLED_APPS配置中。
INSTALLED_APPS = [
'tutorials.apps.TutorialsConfig',
'rest_framework',
]
3.5 定义模型
打开tutorials/models.py,添加Tutorial类。
from django.db import models
class Tutorial(models.Model):
title = models.CharField(max_length=70, blank=False, default='')
description = models.CharField(max_length=200,blank=False, default='')
published = models.BooleanField(default=False)
该模型包含title,description,published三个字段。
3.6 执行数据迁移
生成中间文件
python manage.py makemigrations tutorials
生成文件在tutorials\migrations文件夹下。
执行数据库迁移
python manage.py migrate tutorials
这时数据库已创建好表Tutorial。
3.7 为模型创建序列化类
需要创建TutorialSerializer类来管理序列化/反序列化Json数据。 目标类需要继承至rest_framework.serializers.ModelSerializer。父类将自动获取字段集合和验证器。新建tutorials/serializers.py文件。
from rest_framework import serializers
from tutorials.models import Tutorial
class TutorialSerializer(serializers.ModelSerializer):
class Meta:
model = Tutorial
fields = ('id',
'title',
'description',
'published')
在内置类Meta,我们定义了两个属性:
- model:用于序列化的模型
- fields:元组类型,需要序列化的字段名称
注意这里id字段是Django自动生成,也需要包含在字段中。
3.8 定义路由
在tutorials文件夹下新建urls.py文件,
from django.conf.urls import url
from tutorials import views
urlpatterns = [
url(r'^api/tutorials$', views.tutorial_list),
url(r'^api/tutorials/(?P<pk>[0-9]+)$', views.tutorial_detail),
url(r'^api/tutorials/published$', views.tutorial_list_published)
]
把app的路由添加到项目的urlpatterns中。
from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('tutorials.urls')),
]
3.9 编写API视图
from django.shortcuts import render
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework import status
from tutorials.models import Tutorial
from tutorials.serializers import TutorialSerializer
from rest_framework.decorators import api_view
@api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(request):
if request.method == 'GET':
tutorials = Tutorial.objects.all()
title = request.query_params.get('title', None)
if title is not None:
tutorials = tutorials.filter(title__icontains=title)
tutorials_serializer = TutorialSerializer(tutorials, many=True)
return JsonResponse(tutorials_serializer.data, safe=False)
# 'safe=False' for objects serialization
elif request.method == 'POST':
tutorial_data = JSONParser().parse(request)
tutorial_serializer = TutorialSerializer(data=tutorial_data)
if tutorial_serializer.is_valid():
tutorial_serializer.save()
return JsonResponse(tutorial_serializer.data, status=status.HTTP_201_CREATED)
return JsonResponse(tutorial_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
count = Tutorial.objects.all().delete()
return JsonResponse({'message': '{} Tutorials were deleted successfully!'.format(count[0])}, status=status.HTTP_204_NO_CONTENT)
@api_view(['GET', 'PUT', 'DELETE'])
def tutorial_detail(request, pk):
try:
tutorial = Tutorial.objects.get(pk=pk)
except Tutorial.DoesNotExist:
return JsonResponse({'message': 'The tutorial does not exist'}, status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
tutorial_serializer = TutorialSerializer(tutorial)
return JsonResponse(tutorial_serializer.data)
elif request.method == 'PUT':
tutorial_data = JSONParser().parse(request)
tutorial_serializer = TutorialSerializer(tutorial, data=tutorial_data)
if tutorial_serializer.is_valid():
tutorial_serializer.save()
return JsonResponse(tutorial_serializer.data)
return JsonResponse(tutorial_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
tutorial.delete()
return JsonResponse({'message': 'Tutorial was deleted successfully!'}, status=status.HTTP_204_NO_CONTENT)
@api_view(['GET'])
def tutorial_list_published(request):
tutorials = Tutorial.objects.filter(published=True)
if request.method == 'GET':
tutorials_serializer = TutorialSerializer(tutorials, many=True)
return JsonResponse(tutorials_serializer.data, safe=False)
- 在编写视图中使用装饰器@api_view限定请求方法。
- 使用tutorial对象实例化tutorial_serializer,tutorial_serializer是一个中间结果,其data字段包含字段值和value值。在这个阶段还没有完成序列化工作,只是将模型字段存储到字典中。
- 使用JsonResponse将字典序列化为字符串并返回结果。
- 使用JSONParser().parse(request)方法从表单中反序列化,该方法的返回值为字典。
3.10 启动应用
python manage.py runserver
启动运用以后就可以测试了。
3.11 添加跨域访问限制
在学习阶段这个步骤可以忽略。配置跨域访问是允许非同源请求可以正常获取数据。Django使用cors-headers组件实现。
安装cors-headers
pip install django-cors-headers
配置cors-headers
打开项目setting.py文件,添加:
INSTALLED_APPS = [
'tutorials.apps.TutorialsConfig',
'rest_framework',
'corsheaders',
]
添加中间层类。
MIDDLEWARE = [
# CORS
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
]
添加配置项
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'http://localhost:8081',
)
- CORS_ORIGIN_ALLOW_ALL如果为True,则接收所有非同源请求。与此相反。默认为False,False情况下仅在CORS_ORIGIN_WHITELIST名单中源才允许访问,源组成为访问协议+host+端口号
- CORS_ORIGIN_WHITELIST,非同源白名单
4 使用Postman测试API
通过Postman发起不同类别的请求,测试结果查看引用1。
5 横向比对Java的Springboot框架
相比于使用Django构建Restful接口,使用Springboot构建Restfu接口非常简单,仅需要添加标注@RestController即可实现Restful接口。
package com.zzl.controller;
import com.zzl.domain.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/")
@RestController
public class TestController {
@GetMapping("/test")
public User helloWorld(){
User u = new User();
u.id = "1";
u.name = "zzl";
return u;