第十二章 构建API

来源:互联网 发布:安卓软件应用 编辑:程序博客网 时间:2024/06/05 11:15

12 构建API

在上一章中,你构建了一个学生注册和课程报名系统。你创建了显示课程内容的视图,并学习了如何使用Django的缓存框架。在本章中,你会学习以下知识点:

  • 构建一个RESTful API
  • 为API视图处理认证和权限
  • 创建API视图集和路由

12.1 构建RESTful API

你可能想要创建一个接口,让其它服务可以与你的web应用交互。通过构建一个API,你可以允许第三方以编程方式使用信息和操作你的应用。

你可以通过很多方式构建API,但最好是遵循REST原则。REST架构是表述性状态传递(Representational State Transfer)的缩写。RESTful API是基于资源的。你的模型代表资源,HTTP方法(比如GET,POST,PUT或DELETE)用于检索,创建,更新或者删除对象。HTTP响应代码也可以在这个上下文中使用。返回的不同HTTP响应代码表示HTTP请求的结果,比如2XX响应代码表示成功,4XX表示错误等等。

RESTful API最常用的交互数据的格式是JSON和XML。我们将为项目构建一个JSON序列化的REST API。我们的API会提供以下功能:

  • 检索主题
  • 检索可用的课程
  • 检索课程内容
  • 报名参加课程

我们可以通过Django创建自定义视图,从头开始构建API。但是有很多第三方模块可以简化创建API,其中最流行的是Django Rest Framework

12.1.1 安装Django Rest Framework

Django Rest Framework可以很容易的为项目构建REST API。你可以在这里查看所有文档。

打开终端,使用以下命令安装框架:

pip install djangorestframework
  • 1
  • 1

编辑educa项目的settings.py文件,在INSTALLED_APPS设置中添加rest_framework

INSTALLED_APPS = [    # ...    'rest_framework',]
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

然后在settings.py文件中添加以下代码:

REST_FRAMEWORK = {    'DEFAULT_PREMISSION_CLASSES': [        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'    ]}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

你可以使用REST_FRAMEWORK设置为API提供一个特定配置。REST Framework提供了大量设置来配置默认行为。DEFAULT_PREMISSION_CLASSES设置指定读取,创建,更新或者删除对象的默认权限。我们设置DjangoModelPermissionsOrAnonReadOnly是唯一的默认权限类。这个类依赖Django的权限系统,允许用户创建,更新或删除对象,同时为匿名用户提供只读访问。之后你会学习更多关于权限的内容。

你可以访问这里查看完整的REST Framework可用设置列表。

12.1.2 定义序列化器

设置REST Framework之后,我们需要指定如何序列化我们的数据。输出数据必须序列化为指定格式,输入数据会反序列化处理。框架为单个类构建序列化器提供了以下类:

  • Serializer:为普通Python类实例提供序列化
  • ModelSerializer:为模型实例提供序列化
  • HyperlinkedModelSerializer:与ModelSerializer一样,但使用链接而不是主键表示对象关系

让我们构建第一个序列化器。在courses应用目录中创建以下文件结构:

api/    __init__.py    serializers.py
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

我们会在api目录中构建所有API功能,保持良好的文件结构。编辑serializers.py文件,并添加以下代码:

from rest_framework import serializersfrom ..models import Subjectclass SubjectSerializer(serializers.ModelSerializer):    class Meta:        model = Subject        fields = ('id', 'title', 'slug')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这是Subject模型的序列化器。序列化器的定义类似于Django的FormModelForm类。Meta类允许你指定序列化的模型和序列化中包括的字段。如果没有设置fields属性,则会包括所有模型字段。

让我们试试序列化器。打开终端执行Python manage.py shell命令,然后执行以下代码:

>>> from courses.models import Subject>>> from courses.api.serializers import SubjectSerializer>>> subject = Subject.objects.latest('id')>>> serializer = SubjectSerializer(subject)>>> serializer.data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

在这个例子中,我们获得一个Subject对象,创建一个SubjectSerializer实例,然后访问序列化的数据。你会看到以下输出:

{'id': 4, 'slug': 'mathematics', 'title': 'Mathematics'}
  • 1
  • 1

正如你所看到的,模型数据转换为python的原生数据类型。

12.1.3 理解解析器和渲染器

在HTTP响应中返回序列化的数据之前,需要把它渲染为特定格式。同样的,当你获得HTTP请求时,在你操作它之前,需要解析传入的数据并反序列化数据。REST Framework包括渲染器和解析器来处理这些操作。

让我们看看如何解析收到的数据。给定一个JSON字符串输入,你可以使用REST Framework提供的JSONParser类转换为Python对象。在Python终端中执行以下代码:

from io import BytesIOfrom rest_framework.parsers import JSONParserdata = b'{"id":4,"title":"Music","slug":"music"}'JSONParser().parse(BytesIO(data))
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

你会看到以下输出:

{'id': 4, 'title': 'Music', 'slug': 'music'}
  • 1
  • 1

REST Framework还包括Renderer类,允许你格式化API响应。框架通过内容协商决定使用哪个渲染器。它检查请求的Accept头,决定响应期望的内容类型。根据情况,渲染器由URL格式后缀确定。例如,触发JSONRenderer的访问会返回JSON响应。

回到终端执行以下代码,从上一个序列化器例子中渲染serializer对象:

>>> from rest_framework.renderers import JSONRenderer>>> JSONRenderer().render(serializer.data)
  • 1
  • 2
  • 1
  • 2

你会看到以下输出:

b'{"id":4,"title":"Mathematics","slug":"mathematics"}'
  • 1
  • 1

我们使用JSONRenderer渲染序列化的数据位JSON。默认情况下,REST Framework使用两个不同的渲染器:JSONRendererBrowsableAPIRenderer。后者提供一个web接口,可以很容易的浏览你的API。你可以在REST_FRAMEWORK设置的DEFAULT_RENDERER_CLASSES选项中修改默认的渲染器类。

你可以查看更多关于渲染器和解析器的信息。

12.1.4 构建列表和详情视图

REST Framework自带一组构建API的通用视图和mixins。它们提供了检索,创建,更新或删除模型对象的功能。你可以在这里查看REST Framework提供的所有通用的mixins和视图。

让我们创建检索Subject对象的列表和详情视图。在courses/api/目录中创建views.py文件,并添加以下代码:

from rest_framework import genericsfrom ..models import Subjectfrom .serializers import SubjectSerializerclass SubjectListView(generics.ListAPIView):    queryset = Subject.objects.all()    serializer_class = SubjectSerializerclass SubjectDetailView(generics.RetrieveAPIView):    queryset = Subject.objects.all()    serializer_class = SubjectSerializer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这段代码中,我们使用了REST Framework的通用ListAPIViewRetrieveAPIView。我们在详情视图中包括一个pk URL参数,来检索给定主键的对象。两个视图都包括以下属性:

  • queryset:用于检索对象的基础QuerySet
  • serializer_class:序列化对象的类。

让我们为视图添加URL模式。在courses/api/目录中创建urls.py文件,并添加以下代码:

from django.conf.urls import urlfrom . import viewsurlpatterns = [    url(r'^subjects/$', views.SubjectListView.as_view(), name='subject_list'),    url(r'^subjects/(?P<pk>\d+)/$', views.SubjectDetailView.as_view(), name='subject_detail'),]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

编辑educa项目的主urls.py文件,并引入API模式:

urlpatterns = [    # ...    url(r'^api/', include('courses.api.urls', namespace='api')),]
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

我们为API的URL使用api命名空间。使用python manage.py runserver启动开发服务器。打开终端,并使用curl获取http://127.0.0.1:8000/api/subjects/

bogon:educa lakerszhy$ curl http://127.0.0.1:8000/api/subjects/
  • 1
  • 1

你会看到类似以下的响应:

[{"id":4,"title":"Mathematics","slug":"mathematics"},{"id":3,"title":"Music","slug":"music"},{"id":2,"title":"Physics","slug":"physics"},{"id":1,"title":"Programming","slug":"programming"}]
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

HTTP响应包括JSON格式的Subject对象列表。如果你的操作系统没有安装curl,请在这里下载。除了curl,你还可以使用其它工具发送自定义HTTP请求,比如浏览器扩展Postman,你可以在这里下载Postman

在浏览器中打开http://127.0.0.1:8000/api/subjects/。你会看到REST Framework的可浏览API,如下图所示:

这个HTML界面由BrowsableAPIRenderer渲染器提供。你还可以在URL中包括id来访问一个Subject对象的API详情视图。在浏览器中打开http://127.0.0.1:8000/api/subjects/1/。你会看到单个Subject对象以JSON格式渲染。

12.1.5 创建嵌套的序列化器

我们将为Course模型创建一个序列化器。编辑api/serializers.py文件,并添加以下代码:

from ..models import Courseclass CourseSerializer(serializers.ModelSerializer):    class Meta:        model = Course        fields = ('id', 'subject', 'title', 'slug',             'overview', 'created', 'owner', 'modules')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

让我们看看一个Course对象是如何被序列化的。在终端执行python manage.py shell,然后执行以下代码:

>>> from rest_framework.renderers import JSONRenderer>>> from courses.models import Course>>> from courses.api.serializers import CourseSerializer>>> course = Course.objects.latest('id')>>> serializer = CourseSerializer(course)>>> JSONRenderer().render(serializer.data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

你获得的JSON对象包括我们在CourseSerializer中指定的字段。你会看到modules管理器的关联对象被序列化为主键列表,如下所示:

"modules": [17, 18, 19, 20, 21, 22]
  • 1
  • 1

我们想包括每个单元的更多信息,所以我们需要序列化Module对象,并且嵌套它们。修改api/serializers.py文件中的上一段代码,如下所示:

from ..models import Course, Moduleclass ModuleSerializer(serializers.ModelSerializer):    class Meta:        model = Module        fields = ('order', 'title', 'description')class CourseSerializer(serializers.ModelSerializer):    modules = ModuleSerializer(many=True, read_only=True)    class Meta:        model = Course        fields = ('id', 'subject', 'title', 'slug',             'overview', 'created', 'owner', 'modules')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们定义了ModuleSerializer,为Module模型提供了序列化。然后我们添加modules属性到CourseSerializer来嵌套ModuleSerializer序列化器。我们设置many=True表示正在序列化的是多个对象。read_only参数表示该字段是可读的,并且不应该包括在任何输入中来创建或更新对象。

打开终端,并再创建一个CourseSerializer实例。使用JSONRenderer渲染序列化器的data属性。这次,单元列表被嵌套的ModuleSerializer序列化器序列化,如下所示:

"modules": [    {        "order": 0,        "title": "Django overview",        "description": "A brief overview about the Web Framework."    },     {        "order": 1,        "title": "Installing Django",        "description": "How to install Django."    },    ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

你可以在这里阅读更多关于序列化器的信息。

12.1.6 构建自定义视图

REST Framework提供了一个APIView类,可以在Django的View类之上构建API功能。APIView类与View类不同,它使用REST Framework的自定义RequestResponse对象,并且处理APIException异常返回相应的HTTP响应。它还包括一个内置的认证和授权系统来管理视图的访问。

我们将为用户创建课程报名的视图。编辑api/views.py文件,并添加以下代码:

from django.shortcuts import get_object_or_404from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom ..models import Courseclass CourseEnrollView(APIView):    def post(self, request, pk, format=None):        course = get_object_or_404(Course, pk=pk)        course.students.add(request.user)        return Response({'enrolled': True})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

CourseEnrollView视图处理用户报名参加课程。上面的代码完成以下任务:

  • 我们创建了一个继承自APIView的自定义视图。
  • 我们为POST操作定义了post()方法。这个视图不允许其它HTTP方法。
  • 我们期望URL参数pk包含课程ID。我们用给定的pk参数检索课程,如果没有找到则抛出404异常。
  • 我们添加当前对象到Course对象的多对多关系students中,并返回成功的响应。

编辑api/urls.py文件,并为CourseEnrollView视图添加URL模式:

url(r'^courses/(?P<pk>\d+)/enroll/$', views.CourseEnrollView.as_view(), name='course_enroll'),
  • 1
  • 1

理论上,我们现在可以执行一个POST请求,为当前用户报名参加一个课程。但是,我们需要识别用户,并阻止未认证用户访问这个视图。让我们看看API认证和权限是如何工作的。

12.1.7 处理认证

REST Framework提供了识别执行请求用户的认证类。如果认证成功,框架会在request.user中设置认证的User对象。否则设置为Django的AnonymousUser实例。

REST Framework提供以下认证后台:

  • BasicAuthentication:HTTP基础认证。客户端用Base64在Authorization HTTP头中发送用户和密码。你可以在这里进一步学习。
  • TokenAuthentication:基于令牌的认证。一个Token模型用于存储用户令牌。用户在AuthorizationHTTP头中包括用于认证的令牌。
  • SessionAuthentication:使用Django的会话后台用于认证。当执行从你的网站前端到API的AJAX请求时,这个后台非常有用。

你可以通过继承REST Framework提供的BaseAuthentication类,并覆写authenticate()方法来构建自定义认证后台。

你可以基于单个视图设置认证,或者用DEFAULT_AUTHENTICATION_CLASSES设置为全局认证。

认证只识别执行请求的用户。它不会允许或阻止访问视图。你必须使用权限来显示访问视图。

你可以在这里查看所有关于认证的信息。

让我们添加BasicAuthentication到我们的视图。编辑courses应用的api/views.py文件,并添加authentication_classes属性到CourseEnrollView

from rest_framework.authentication import BasicAuthenticationclass CourseEnrollView(APIView):    authentication_classes = (BasicAuthentication, )    # ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

用户将通过设置在HTTP请求中的Authorization头的证书识别。

12.1.8 添加权限到视图

REST Framework包括一个权限系统,用于限制视图的访问。REST Framework的一些内置权限是:

  • AllowAny:不限制访问,不管用户是否认证。
  • IsAuthenticated:只允许认证的用户访问。
  • IsAuthenticatedOrReadOnly:认证用户可以完全访问。匿名用户只允许执行读取方法,比如GET,HEAD或OPTIONS。
  • DjangoModelPermissions:捆绑到django.contrib.auth的权限。视图需要一个queryset属性。只有分配了模型权限的认证用户才能获得权限。
  • DjangoObjectPermissions:基于单个对象的Django权限。

如果用户被拒绝访问,他们通常会获得以下某个HTTP错误代码:

  • HTTP 401:未认证
  • HTTP 403:没有权限

你可以在这里阅读更多关于权限的信息。

编辑courses应用的api/views.py文件,并在CourseEnrollView中添加permission_classes属性:

from rest_framework.authentication import BasicAuthenticationfrom rest_framework.permissions import IsAuthenticatedclass CourseEnrollView(APIView):    authentication_classes = (BasicAuthentication, )    permission_classes = (IsAuthenticated, )    # ..
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们引入了IsAuthenticated权限。这会阻止匿名用户访问这个视图。现在我们可以执行POST请求到新的API方法。

确保开发服务器正在运行。打开终端并执行以下命令:

curl -i -X POST http://127.0.0.1:8000/api/courses/1/enroll/
  • 1
  • 1

你会获得以下响应:

HTTP/1.0 401 UNAUTHORIZED...{"detail": "Authentication credentials were not provided."}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

因为我们是未认证用户,所以如期获得401 HTTP代码。让我们用其中一个用户进行基础认证。执行以下命令:

curl -i -X POST -u student:password http://127.0.0.1:8000/api/courses/1/enroll/
  • 1
  • 1

用已存在用户凭证替换student:password。你会获得以下响应:

HTTP/1.0 200 OK...{"enrolled": true}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

你可以访问管理站点,检查用户是否报名参加课程。

12.1.9 创建视图集和路由

ViewSets允许你定义你的API交互,并让REST Framework用Router对象动态构建URL。通过视图集,你可以避免多个视图的重复逻辑。视图集包括典型的创建,检索,更新,删除操作,分别是list()create()retrieve()update()partial_update()destroy()

让我们为Course模型创建一个视图集。编辑api/views.py文件,并添加以下代码:

from rest_framework import viewsetsfrom .serializers import CourseSerializerclass CourseViewSet(viewsets.ReadOnlyModelViewSet):    queryset = Course.objects.all()    serializer_class = CourseSerializer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们从ReadOnlyModelViewSet继承,它提供了只读操作list()retrieve(),用于列出对象或检索单个对象。编辑api/urls.py文件,并为我们的视图集创建一个路由:

from django.conf.urls import url, includefrom . import viewsfrom rest_framework import routersrouter = routers.DefaultRouter()router.register('courses', views.CourseViewSet)urlpatterns = [    # ...    url(r'^', include(router.urls)),]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我们创建了一个DefaultRouter对象,并用courses前缀注册我们的视图集。路由负责为我们的视图集自动生成URL。

在浏览器中打开http://127.0.0.1:8000/api/。你会看到路由在它的基础URL中列出所有视图集,如下图所示:

你现在可以访问http://127.0.0.1:8000/api/courses/检索课程列表。

你可以在这里进一步学习视图集。你还可以在这里查看更多关于路由的信息。

12.1.10 添加额外操作到视图集

你可以添加额外操作到视图集中。让我们把之前的CourseEnrollView视图为一个自定义视图集操作。编辑api/views.py文件,并修改CourseViewSet类:

from rest_framework.decorators import detail_routeclass CourseViewSet(viewsets.ReadOnlyModelViewSet):    queryset = Course.objects.all()    serializer_class = CourseSerializer    @detail_route(        methods=['post'],        authentication_classes=[BasicAuthentication],        permission_classes=[IsAuthenticated]    )    def enroll(self, request, *args, **kwargs):        course = self.get_object()        course.students.add(request.user)        return Response({'enrolled': True})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我们添加了一个自定义的enroll()方法,它代表这个视图集的一个额外操作。上面的代码执行以下任务:

  • 我们使用框架的detail_route装饰器,指定这是在单个对象上执行的操作。
  • 装饰器允许我们为操作添加自定义属性。我们指定这个视图只允许POST方法,并设置了认证和权限类。
  • 我们使用self.get_object()检索Courses对象。
  • 我们把当前用户添加到students多对多关系中,并返回一个自定义的成功响应。

编辑api/urls.py文件,移除以下URL,因为我们不再需要它:

url(r'^courses/(?P<pk>\d+)/enroll/$', views.CourseEnrollView.as_view(), name='course_enroll'),
  • 1
  • 1

然后编辑api/views.py文件,移除CourseEnrollView类。

现在,报名参加课程的URL由路由自动生成。因为它使用操作名enroll,所以URL保持不变。

12.1.11 创建自定义权限

我们希望学生可以访问它们报名的课程内容。只有报名的学生才可以访问课程内容。最好的实现方式是使用一个自定义权限类。Django提供的BasePermission类允许你定义以下方法:

  • has_permission():视图级别的权限检查
  • has_object_permission():实例级别的权限检查

如果获得访问权限,这些方法返回True,否则返回False。在courses/api/目录中创建permissions.py文件,并添加以下代码:

from rest_framework.permissions import BasePermissionclass IsEnrolled(BasePermission):    def has_object_permission(self, request, view, obj):        return obj.students.filter(id=request.user.id).exists()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们从BasePermission类继承,并覆写has_object_permission()。我们检查执行请求的用户是否存在Course对象的students关系中。我们下一步会使用IsEnrolled权限。

12.1.12 序列化课程内容

我们需要序列化课程内容。Content模型包括一个通用外键,允许我们访问关联对象的不同内容模型。但是,我们在上一章为所有内容模型添加了通用的render()方法。我们可以使用这个方法为API提供渲染后的内容。

编辑courses应用的api/serializers.py文件,并添加以下代码:

from ..models import Contentclass ItemRelatedField(serializers.RelatedField):    def to_representation(self, value):        return value.render()class ContentSerializer(serializers.ModelSerializer):    item = ItemRelatedField(read_only=True)    class Meta:        model = Content        fields = ('order', 'item')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这段代码中,通过继承REST Framework提供的RelatedField序列化器字段和覆写to_representation()方法,我们定义了一个自定义字段。我们为Content模型定义了ContentSerializer序列化器,并用自定义字段作为item通用外键。

我们需要一个包括内容的Module模型的替换序列化器,以及一个扩展的Course序列化器。编辑api/serializers.py文件,并添加以下代码:

class ModuleWithContentsSerializer(serializers.ModelSerializer):    contents = ContentSerializer(many=True)    class Meta:        model = Module        fields = ('order', 'title', 'description', 'contents')class CourseWithContentsSerializer(serializers.ModelSerializer):    modules = ModuleWithContentsSerializer(many=True)    class Meta:        model = Course        fields = ('id', 'subject', 'title', 'slug', 'overview',             'created', 'owner', 'modules')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

让我们创建一个模仿retrieve()操作,但是包括课程内容的视图。编辑api/views.py文件,并在CourseViewSet类中添加以下方法:

from .permissions import IsEnrolledfrom .serializers import CourseWithContentsSerializerclass CourseViewSet(viewsets.ReadOnlyModelViewSet):    # ...    @detail_route(        methods=['get'],        serializer_class=CourseWithContentsSerializer,        authentication_classes=[BasicAuthentication],        permission_classes=[IsAuthenticated, IsEnrolled]    )    def contents(self, request, *args, **kwargs):        return self.retrieve(request, *args, **kwargs)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这个方法执行以下任务:

  • 我们使用detail_route装饰器指定该操作在单个对象上执行。
  • 我们指定该操作只允许GET方法。
  • 我们使用新的CourseWithContentsSerializer序列化器类,它包括渲染的课程内容。
  • 我们使用IsAuthenticated和自定义的IsEnrolled权限。这样可以确保只有报名的用户可以访问课程内容。
  • 我们使用存在的retrieve()操作返回课程对象。

在浏览器中打开http://127.0.0.1:8000/api/courses/1/contents/。如果你用正确证书访问视图,你会看到课程的每个单元,包括渲染后的课程内容的HTML,如下所示:

{   "order": 0,   "title": "Installing Django",   "description": "",   "contents": [        {        "order": 0,        "item": "<p>Take a look at the following video for installing Django:</p>\n"        },         {        "order": 1,        "item": "\n<iframe width=\"480\" height=\"360\" src=\"http://www.youtube.com/embed/bgV39DlmZ2U?wmode=opaque\" frameborder=\"0\" allowfullscreen></iframe>\n\n"        }     ]    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

你已经构建了一个简单的API,允许其它服务通过编程方式访问course应用。REST Framework还允许你用ModelViewSet视图集管理创建和编辑对象。我们已经学习了Django Rest Framework的主要部分,但你仍可以在这里进一步学习它的特性。

12.2 总结

在这一章中,你创建了一个RESTful API,可以让其它服务与你的web应用交互。

额外的第十三章可以在这里下载。它教你如何使用uWSGINGINX构建一个生产环境。你还会学习如何实现一个自定义的中间件和创建自定义的管理命令。

你已经到达了本书的结尾。恭喜你!你已经学会了用Django构建一个成功的web应用所需要的技巧。本书指导你完成开发实际项目,以及将Django与其它技术结合。现在你已经准备好创建自己的Django项目,不管是一个简单的原型还是一个大型的web应用。

祝你下一次Django冒险活动好运!

原创粉丝点击