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=