首发于 Django开发
手把手教你用Django实现RESTful接口

手把手教你用Django实现RESTful接口

1 阅读说明

  1. 本篇阅读对象定位为具有一定Django使用经验的开发人员;
  2. 本篇需要10min左右阅读。

2 Rest Api架构

随着前后端分离,RESTful风格接口正越来越受到欢迎。 本篇文章介绍如何使用Django框架实现RESTFful接口。

各个组件说明:

  1. Url Patterns, 将请求路由到具体处理的视图;
  2. View,处理HTTP请求并返回HTTP Response;
  3. Serializer,序列化/反序列化模型数据;
  4. 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;