概述

在我们之前的讲解中,我们曾经提到过目前大部分的项目是前后端分离的,即后端提供标准的接口,前端通过调用接口获取数据并进行渲染。

同时,随时目前微服务架构的不断流行,一个项目中可能会包含很多个功能模块,多个功能模块之间大部分也都是通过接口进行相互调用的。

而之前我们一直学习的View层其实更注重于Template渲染等相关的功能。

为了能够更加方便的实现标准化的HTTP接口,Django提供了一套专门的框架Django REST Framework用于快速提供REST风格的HTTP接口供外部访问。

Django REST Framework概述

Django REST Framework提供了一套丰富的框架,可以让我们轻松的:

  1. 提供标准的开放API
  2. 配置合适的权限控制

安装

Step1: 安装Django REST Framework相关的依赖库

  1. pip3 install djangorestframework
  2. pip3 install markdown
  3. pip3 install django-filter

Step2: 在项目的settings.pyINSTALLED_APPS中增加rest_framework

Step3: 添加REST接口页面的登录、退出视图注册到项目的urls.py中:

  1. urlpatterns = [
  2. ...
  3. path(r'^api-auth/', include("rest_framework.urls")),
  4. ]

Step4: 在项目的settings.py文件中增加REST_FRAMEWORK相关配置:

  1. REST_FRAMEWORK = {
  2. # Use Django's standard `django.contrib.auth` permissions,
  3. # or allow read-only access for unauthenticated users.
  4. 'DEFAULT_PERMISSION_CLASSES': [
  5. 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
  6. ]
  7. }

上述配置表示rest framework的默认接口权限为标准的auth鉴权且针对未授权用户开放只读权限。

到此为止,我们的Django REST Framework就已经开发完成了。

Django REST Framework快速上手

下面,我们来通过一个实例演示如何通过Django REST Framework来提供对应的接口。

其实,使用过程非常简单,我们只需要将对应的model注册到url中即可,省去了View的阶段。

具体来说,修改项目的urls.py文件,增加如下内容:

  1. from rest_framework import routers, serializers, viewsets
  2. # Serializers define the API representation.
  3. class UserSerializer(serializers.HyperlinkedModelSerializer):
  4. class Meta:
  5. model = User # 对应哪个模型
  6. fields = ['url', 'username', 'email', 'is_staff'] # 返回哪些字段
  7. # ViewSets define the view behavior.
  8. class UserViewSet(viewsets.ModelViewSet):
  9. queryset = User.objects.all()
  10. serializer_class = UserSerializer
  11. class JobSerializer(serializers.HyperlinkedModelSerializer):
  12. class Meta:
  13. model = Job
  14. fields = '__all__'
  15. class JobViewSet(viewsets.ModelViewSet):
  16. """
  17. API endpoint that allows groups to be viewed or edited.
  18. """
  19. queryset = Job.objects.all()
  20. serializer_class = JobSerializer
  21. router = routers.DefaultRouter()
  22. router.register(r'users', UserViewSet)
  23. router.register(r'jobs', JobViewSet)
  24. urlpatterns = [
  25. ...
  26. path('api/', include(router.urls)),
  27. ]

可以看到,我们在上述代码中,分别创建了User和Job的Serializer和ViewSet,并将其注册到路由。

此时,直接访问http://127.0.0.1:8080/api/ 地址,你就已经可以看到REST Framework相关的API页面并进行操作了。

Django REST Framework接口扩展

有时,我们需要在接口请求中增加某些字段的逻辑校验,或者是我们的一个表中包含了一些外键,这时,我们需要对Serializer进行扩展满足业务需求:

  1. class TaskSerializer(serializers.HyperlinkedModelSerializer):
  2. """
  3. # Serializer类
  4. """
  5. class Meta:
  6. """
  7. # 元数据
  8. """
  9. model = Task
  10. fields = (
  11. "name", "status", "device_id", "action", "url"
  12. )
  13. def validate(self, attrs):
  14. """
  15. # 数据验证
  16. """
  17. if "device_id" not in self.context["request"].data:
  18. raise Exception("device_id is required")
  19. device_id = self.context["request"].data["device_id"]
  20. try:
  21. Device.objects.get(pk=device_id)
  22. except ObjectDoesNotExist:
  23. raise Exception("device_id %s not exists" % device_id)
  24. attrs["device_id"] = self.context["request"].data["device_id"]
  25. return attrs
  26. def create(self, validated_data):
  27. """
  28. # 处理内置逻辑
  29. """
  30. device = Device.objects.get(pk=validated_data["device_id"])
  31. return Task.objects.create(device=device, **validated_data)

以上述代码为例,我们在Serializer类中增加了validatecreate两个函数。

这两个函数都是Django REST Framework中有特殊函数的含义名称。

先来看validate:

validate函数是指可以在接口被真正处理前,对传入的参数进行校验和补充。

validate函数接收一个self和attrs属性,我们可以通过self.context["request"].data来读取HTTP原始请求数据进行参数校验,同时可以通过给attr属性赋值使得其可以在create函数中直接使用。

再看来create函数:

create函数会在validate函数调用返回后再次进行调用,本质上是用于重写数据库写入逻辑,例如对于外键这种场景,我们就需要重写数据库写入逻辑。

其中,create函数同样接收两个参数,分别是self和validated_data,而validated_data其实就是在validate函数中返回的attrs属性值。

另外需要说明的时,在fields属性中,如果设置为__all__时,我们默认是无法查看到外键关联的字段的,此时,有两种方法可以解决该问题:

  1. 方法一: fields属性中,补充model_name_id从而显示对应外键的主键值。
  2. 方法二: 在Meta类下,新增depth属性,并设置为大于等于1的数,此时,会将外键关联的数据进行嵌套查询并完整显示出来。其中,depth表示嵌套搜索的层数。

Django REST Framework自定义接口

可以看到,在上面的例子中,我们会非常少的代码就实现了将模型映射到接口中,并对外提供。

但你应该会发现,上面的例子中仅仅是将模型映射到接口并直接对外暴露,这会导致我们无法加入自定义的业务逻辑。

例如,有时我们一个业务操作可能会涉及到多张表的增、删、改、查操作等,这时应该怎么处理呢?

Django REST Framework其实也提供了一种自定义接口逻辑的方法,我们以下面的例子进行说明:

  1. from django.urls import path
  2. from rest_framework.decorators import api_view
  3. from rest_framework.decorators import permission_classes
  4. from rest_framework.response import Response
  5. from rest_framework.permissions import IsAuthenticated
  6. @api_view(["GET", "POST"])
  7. @permission_classes([IsAuthenticated])
  8. def get_self_task(request):
  9. """
  10. # 获取当前的设备的Task任务
  11. """
  12. if request.method == "GET":
  13. host_ip = request.GET["host_ip"]
  14. else:
  15. host_ip = request.data["host_ip"]
  16. return Response({"code": 200, "host_ip": host_ip})
  17. urlpatterns = [
  18. path('api/get_self_task', get_self_task)
  19. ]

可以看到,在上面的例子中,我们定义了一个get_self_task函数,这个函数可以接收GET和POST请求。

对于GET请求,从url中获取host_ip信息,对于POST请求,从body中获取host_ip信息,并将相关结果进行返回。

其中,@permission_classes([IsAuthenticated])是必不可少的,因为我们之前的settings.py 中设置的相关权限的配置,因此需要在所有自定义的api_view函数中都需要增加该装饰器。

参考资源

  1. Django REST Framework官方