12 構(gòu)建API
在上一章中柬帕,你構(gòu)建了一個學生注冊和課程報名系統(tǒng)。你創(chuàng)建了顯示課程內(nèi)容的視圖,并學習了如何使用Django的緩存框架隔节。在本章中鹅经,你會學習以下知識點:
- 構(gòu)建一個RESTful API
- 為API視圖處理認證和權(quán)限
- 創(chuàng)建API視圖集和路由
12.1 構(gòu)建RESTful API
你可能想要創(chuàng)建一個接口,讓其它服務可以與你的web應用交互怎诫。通過構(gòu)建一個API瘾晃,你可以允許第三方以編程方式使用信息和操作你的應用。
你可以通過很多方式構(gòu)建API幻妓,但最好是遵循REST原則蹦误。REST架構(gòu)是表述性狀態(tài)傳遞(Representational State Transfer
)的縮寫。RESTful API是基于資源的肉津。你的模型代表資源强胰,HTTP方法(比如GET,POST妹沙,PUT或DELETE)用于檢索偶洋,創(chuàng)建,更新或者刪除對象距糖。HTTP響應代碼也可以在這個上下文中使用玄窝。返回的不同HTTP響應代碼表示HTTP請求的結(jié)果,比如2XX響應代碼表示成功悍引,4XX表示錯誤等等恩脂。
RESTful API最常用的交互數(shù)據(jù)的格式是JSON和XML。我們將為項目構(gòu)建一個JSON序列化的REST API趣斤。我們的API會提供以下功能:
- 檢索主題
- 檢索可用的課程
- 檢索課程內(nèi)容
- 報名參加課程
我們可以通過Django創(chuàng)建自定義視圖俩块,從頭開始構(gòu)建API。但是有很多第三方模塊可以簡化創(chuàng)建API浓领,其中最流行的是Django Rest Framework
玉凯。
12.1.1 安裝Django Rest Framework
Django Rest Framework
可以很容易的為項目構(gòu)建REST API。你可以在這里查看所有文檔镊逝。
打開終端壮啊,使用以下命令安裝框架:
pip install djangorestframework
編輯educa
項目的settings.py
文件歹啼,在INSTALLED_APPS
設置中添加rest_framework
:
INSTALLED_APPS = [
# ...
'rest_framework',
]
然后在settings.py
文件中添加以下代碼:
REST_FRAMEWORK = {
'DEFAULT_PREMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
你可以使用REST_FRAMEWORK
設置為API提供一個特定配置。REST Framework提供了大量設置來配置默認行為浴滴。DEFAULT_PREMISSION_CLASSES
設置指定讀取微王,創(chuàng)建炕倘,更新或者刪除對象的默認權(quán)限啊央。我們設置DjangoModelPermissionsOrAnonReadOnly
是唯一的默認權(quán)限類瓜饥。這個類依賴Django的權(quán)限系統(tǒng)乓土,允許用戶創(chuàng)建坎炼,更新或刪除對象谣光,同時為匿名用戶提供只讀訪問蟀悦。之后你會學習更多關(guān)于權(quán)限的內(nèi)容日戈。
你可以訪問這里查看完整的REST Framework可用設置列表。
12.1.2 定義序列化器
設置REST Framework之后弯屈,我們需要指定如何序列化我們的數(shù)據(jù)资厉。輸出數(shù)據(jù)必須序列化為指定格式湘捎,輸入數(shù)據(jù)會反序列化處理消痛。框架為單個類構(gòu)建序列化器提供了以下類:
-
Serializer
:為普通Python類實例提供序列化 -
ModelSerializer
:為模型實例提供序列化 -
HyperlinkedModelSerializer
:與ModelSerializer
一樣纱新,但使用鏈接而不是主鍵表示對象關(guān)系
讓我們構(gòu)建第一個序列化器。在courses
應用目錄中創(chuàng)建以下文件結(jié)構(gòu):
api/
__init__.py
serializers.py
我們會在api
目錄中構(gòu)建所有API功能簿废,保持良好的文件結(jié)構(gòu)族檬。編輯serializers.py
文件,并添加以下代碼:
from rest_framework import serializers
from ..models import Subject
class SubjectSerializer(serializers.ModelSerializer):
class Meta:
model = Subject
fields = ('id', 'title', 'slug')
這是Subject
模型的序列化器。序列化器的定義類似于Django的Form
和ModelForm
類换怖。Meta
類允許你指定序列化的模型和序列化中包括的字段。如果沒有設置fields
屬性,則會包括所有模型字段抬探。
讓我們試試序列化器线梗。打開終端執(zhí)行python manage.py shell
命令,然后執(zhí)行以下代碼:
>>> from courses.models import Subject
>>> from courses.api.serializers import SubjectSerializer
>>> subject = Subject.objects.latest('id')
>>> serializer = SubjectSerializer(subject)
>>> serializer.data
在這個例子中烤咧,我們獲得一個Subject
對象,創(chuàng)建一個SubjectSerializer
實例昌阿,然后訪問序列化的數(shù)據(jù)谣沸。你會看到以下輸出:
{'id': 4, 'slug': 'mathematics', 'title': 'Mathematics'}
正如你所看到的鳄抒,模型數(shù)據(jù)轉(zhuǎn)換為Python的原生數(shù)據(jù)類型。
12.1.3 理解解析器和渲染器
在HTTP響應中返回序列化的數(shù)據(jù)之前,需要把它渲染為特定格式辜膝。同樣的清焕,當你獲得HTTP請求時滚停,在你操作它之前键畴,需要解析傳入的數(shù)據(jù)并反序列化數(shù)據(jù)。REST Framework包括渲染器和解析器來處理這些操作。
讓我們看看如何解析收到的數(shù)據(jù)起惕。給定一個JSON字符串輸入涡贱,你可以使用REST Framework提供的JSONParser
類轉(zhuǎn)換為Python對象。在Python終端中執(zhí)行以下代碼:
from io import BytesIO
from rest_framework.parsers import JSONParser
data = b'{"id":4,"title":"Music","slug":"music"}'
JSONParser().parse(BytesIO(data))
你會看到以下輸出:
{'id': 4, 'title': 'Music', 'slug': 'music'}
REST Framework還包括Renderer
類惹想,允許你格式化API響應问词。框架通過內(nèi)容協(xié)商決定使用哪個渲染器嘀粱。它檢查請求的Accept
頭,決定響應期望的內(nèi)容類型豌鸡。根據(jù)情況瞻赶,渲染器由URL格式后綴確定豆混。例如奠滑,觸發(fā)JSONRenderer
的訪問會返回JSON響應淆攻。
回到終端執(zhí)行以下代碼,從上一個序列化器例子中渲染serializer
對象:
>>> from rest_framework.renderers import JSONRenderer
>>> JSONRenderer().render(serializer.data)
你會看到以下輸出:
b'{"id":4,"title":"Mathematics","slug":"mathematics"}'
我們使用JSONRenderer
渲染序列化的數(shù)據(jù)位JSON胸遇。默認情況下,REST Framework使用兩個不同的渲染器:JSONRenderer
和BrowsableAPIRenderer
。后者提供一個web接口,可以很容易的瀏覽你的API。你可以在REST_FRAMEWORK
設置的DEFAULT_RENDERER_CLASSES
選項中修改默認的渲染器類济欢。
12.1.4 構(gòu)建列表和詳情視圖
REST Framework自帶一組構(gòu)建API的通用視圖和mixins。它們提供了檢索羡儿,創(chuàng)建,更新或刪除模型對象的功能。你可以在這里查看REST Framework提供的所有通用的mixins和視圖。
讓我們創(chuàng)建檢索Subject
對象的列表和詳情視圖毁渗。在courses/api/
目錄中創(chuàng)建views.py
文件,并添加以下代碼:
from rest_framework import generics
from ..models import Subject
from .serializers import SubjectSerializer
class SubjectListView(generics.ListAPIView):
queryset = Subject.objects.all()
serializer_class = SubjectSerializer
class SubjectDetailView(generics.RetrieveAPIView):
queryset = Subject.objects.all()
serializer_class = SubjectSerializer
在這段代碼中赎线,我們使用了REST Framework的通用ListAPIView
和RetrieveAPIView
廷没。我們在詳情視圖中包括一個pk
URL參數(shù),來檢索給定主鍵的對象垂寥。兩個視圖都包括以下屬性:
-
queryset
:用于檢索對象的基礎QuerySet
颠黎。 -
serializer_class
:序列化對象的類。
讓我們?yōu)橐晥D添加URL模式滞项。在courses/api/
目錄中創(chuàng)建urls.py
文件狭归,并添加以下代碼:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^subjects/$', views.SubjectListView.as_view(), name='subject_list'),
url(r'^subjects/(?P<pk>\d+)/$', views.SubjectDetailView.as_view(), name='subject_detail'),
]
編輯educa
項目的主urls.py
文件,并引入API模式:
urlpatterns = [
# ...
url(r'^api/', include('courses.api.urls', namespace='api')),
]
我們?yōu)锳PI的URL使用api
命名空間蓖扑。使用python manage.py runserver
啟動開發(fā)服務器唉铜。打開終端,并使用curl
獲取http://127.0.0.1:8000/api/subjects/
:
bogon:educa lakerszhy$ curl http://127.0.0.1:8000/api/subjects/
你會看到類似以下的響應:
[{"id":4,"title":"Mathematics","slug":"mathematics"},
{"id":3,"title":"Music","slug":"music"},
{"id":2,"title":"Physics","slug":"physics"},
{"id":1,"title":"Programming","slug":"programming"}]
HTTP響應包括JSON格式的Subject
對象列表律杠。如果你的操作系統(tǒng)沒有安裝curl
潭流,請在這里下載。除了curl
柜去,你還可以使用其它工具發(fā)送自定義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 創(chuàng)建嵌套的序列化器
我們將為Course
模型創(chuàng)建一個序列化器炎滞。編輯api/serializers.py
文件,并添加以下代碼:
from ..models import Course
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ('id', 'subject', 'title', 'slug',
'overview', 'created', 'owner', 'modules')
讓我們看看一個Course
對象是如何被序列化的诬乞。在終端執(zhí)行python manage.py shell
册赛,然后執(zhí)行以下代碼:
>>> 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)
你獲得的JSON對象包括我們在CourseSerializer
中指定的字段。你會看到modules
管理器的關(guān)聯(lián)對象被序列化為主鍵列表震嫉,如下所示:
"modules": [17, 18, 19, 20, 21, 22]
我們想包括每個單元的更多信息森瘪,所以我們需要序列化Module
對象,并且嵌套它們票堵。修改api/serializers.py
文件中的上一段代碼扼睬,如下所示:
from ..models import Course, Module
class 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')
我們定義了ModuleSerializer
,為Module
模型提供了序列化悴势。然后我們添加modules
屬性到CourseSerializer
來嵌套ModuleSerializer
序列化器窗宇。我們設置many=True
表示正在序列化的是多個對象。read_only
參數(shù)表示該字段是可讀的瞳浦,并且不應該包括在任何輸入中來創(chuàng)建或更新對象担映。
打開終端,并再創(chuàng)建一個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."
},
...
你可以在這里閱讀更多關(guān)于序列化器的信息短蜕。
12.1.6 構(gòu)建自定義視圖
REST Framework提供了一個APIView
類,可以在Django的View
類之上構(gòu)建API功能傻咖。APIView
類與View
類不同朋魔,它使用REST Framework的自定義Request
和Response
對象,并且處理APIException
異常返回相應的HTTP響應卿操。它還包括一個內(nèi)置的認證和授權(quán)系統(tǒng)來管理視圖的訪問警检。
我們將為用戶創(chuàng)建課程報名的視圖孙援。編輯api/views.py
文件,并添加以下代碼:
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from ..models import Course
class 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})
CourseEnrollView
視圖處理用戶報名參加課程扇雕。上面的代碼完成以下任務:
- 我們創(chuàng)建了一個繼承自
APIView
的自定義視圖拓售。 - 我們?yōu)镻OST操作定義了
post()
方法。這個視圖不允許其它HTTP方法镶奉。 - 我們期望URL參數(shù)
pk
包含課程ID础淤。我們用給定的pk
參數(shù)檢索課程,如果沒有找到則拋出404異常哨苛。 - 我們添加當前對象到
Course
對象的多對多關(guān)系students
中鸽凶,并返回成功的響應。
編輯api/urls.py
文件建峭,并為CourseEnrollView
視圖添加URL模式:
url(r'^courses/(?P<pk>\d+)/enroll/$', views.CourseEnrollView.as_view(), name='course_enroll'),
理論上玻侥,我們現(xiàn)在可以執(zhí)行一個POST請求,為當前用戶報名參加一個課程迹缀。但是使碾,我們需要識別用戶,并阻止未認證用戶訪問這個視圖祝懂。讓我們看看API認證和權(quán)限是如何工作的票摇。
12.1.7 處理認證
REST Framework提供了識別執(zhí)行請求用戶的認證類。如果認證成功砚蓬,框架會在request.user
中設置認證的User
對象矢门。否則設置為Django的AnonymousUser
實例。
REST Framework提供以下認證后臺:
-
BasicAuthentication
:HTTP基礎認證灰蛙∷钐蓿客戶端用Base64在Authorization
HTTP頭中發(fā)送用戶和密碼。你可以在這里進一步學習摩梧。 -
TokenAuthentication
:基于令牌的認證物延。一個Token
模型用于存儲用戶令牌。用戶在Authorization
HTTP頭中包括用于認證的令牌仅父。 -
SessionAuthentication
:使用Django的會話后臺用于認證叛薯。當執(zhí)行從你的網(wǎng)站前端到API的AJAX請求時,這個后臺非常有用笙纤。
你可以通過繼承REST Framework提供的BaseAuthentication
類耗溜,并覆寫authenticate()
方法來構(gòu)建自定義認證后臺。
你可以基于單個視圖設置認證省容,或者用DEFAULT_AUTHENTICATION_CLASSES
設置為全局認證抖拴。
認證只識別執(zhí)行請求的用戶。它不會允許或阻止訪問視圖腥椒。你必須使用權(quán)限來顯示訪問視圖阿宅。
你可以在這里查看所有關(guān)于認證的信息候衍。
讓我們添加BasicAuthentication
到我們的視圖。編輯courses
應用的api/views.py
文件家夺,并添加authentication_classes
屬性到CourseEnrollView
:
from rest_framework.authentication import BasicAuthentication
class CourseEnrollView(APIView):
authentication_classes = (BasicAuthentication, )
# ...
用戶將通過設置在HTTP請求中的Authorization
頭的證書識別脱柱。
12.1.8 添加權(quán)限到視圖
REST Framework包括一個權(quán)限系統(tǒng)伐弹,用于限制視圖的訪問拉馋。REST Framework的一些內(nèi)置權(quán)限是:
-
AllowAny
:不限制訪問,不管用戶是否認證惨好。 -
IsAuthenticated
:只允許認證的用戶訪問煌茴。 -
IsAuthenticatedOrReadOnly
:認證用戶可以完全訪問。匿名用戶只允許執(zhí)行讀取方法日川,比如GET蔓腐,HEAD或OPTIONS。 -
DjangoModelPermissions
:捆綁到django.contrib.auth
的權(quán)限龄句。視圖需要一個queryset
屬性回论。只有分配了模型權(quán)限的認證用戶才能獲得權(quán)限。 -
DjangoObjectPermissions
:基于單個對象的Django權(quán)限分歇。
如果用戶被拒絕訪問傀蓉,他們通常會獲得以下某個HTTP錯誤代碼:
-
HTTP 401
:未認證 -
HTTP 403
:沒有權(quán)限
你可以在這里閱讀更多關(guān)于權(quán)限的信息。
編輯courses
應用的api/views.py
文件职抡,并在CourseEnrollView
中添加permission_classes
屬性:
from rest_framework.authentication import BasicAuthentication
from rest_framework.permissions import IsAuthenticated
class CourseEnrollView(APIView):
authentication_classes = (BasicAuthentication, )
permission_classes = (IsAuthenticated, )
# ..
我們引入了IsAuthenticated
權(quán)限葬燎。這會阻止匿名用戶訪問這個視圖。現(xiàn)在我們可以執(zhí)行POST請求到新的API方法缚甩。
確保開發(fā)服務器正在運行谱净。打開終端并執(zhí)行以下命令:
curl -i -X POST http://127.0.0.1:8000/api/courses/1/enroll/
你會獲得以下響應:
HTTP/1.0 401 UNAUTHORIZED
...
{"detail": "Authentication credentials were not provided."}
因為我們是未認證用戶,所以如期獲得401
HTTP代碼擅威。讓我們用其中一個用戶進行基礎認證壕探。執(zhí)行以下命令:
curl -i -X POST -u student:password http://127.0.0.1:8000/api/courses/1/enroll/
用已存在用戶憑證替換student:password
。你會獲得以下響應:
HTTP/1.0 200 OK
...
{"enrolled": true}
你可以訪問管理站點郊丛,檢查用戶是否報名參加課程李请。
12.1.9 創(chuàng)建視圖集和路由
ViewSets
允許你定義你的API交互,并讓REST Framework用Router
對象動態(tài)構(gòu)建URL宾袜。通過視圖集捻艳,你可以避免多個視圖的重復邏輯。視圖集包括典型的創(chuàng)建庆猫,檢索认轨,更新,刪除操作月培,分別是list()
嘁字,create()
恩急,retrieve()
,update()
纪蜒,partial_update()
和destroy()
衷恭。
讓我們?yōu)?code>Course模型創(chuàng)建一個視圖集。編輯api/views.py
文件纯续,并添加以下代碼:
from rest_framework import viewsets
from .serializers import CourseSerializer
class CourseViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Course.objects.all()
serializer_class = CourseSerializer
我們從ReadOnlyModelViewSet
繼承随珠,它提供了只讀操作list()
和retrieve()
,用于列出對象或檢索單個對象猬错。編輯api/urls.py
文件窗看,并為我們的視圖集創(chuàng)建一個路由:
from django.conf.urls import url, include
from . import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register('courses', views.CourseViewSet)
urlpatterns = [
# ...
url(r'^', include(router.urls)),
]
我們創(chuàng)建了一個DefaultRouter
對象,并用courses
前綴注冊我們的視圖集倦炒。路由負責為我們的視圖集自動生成URL显沈。
在瀏覽器中打開http://127.0.0.1:8000/api/
。你會看到路由在它的基礎URL中列出所有視圖集逢唤,如下圖所示:
你現(xiàn)在可以訪問http://127.0.0.1:8000/api/courses/
檢索課程列表拉讯。
你可以在這里進一步學習視圖集。你還可以在這里查看更多關(guān)于路由的信息鳖藕。
12.1.10 添加額外操作到視圖集
你可以添加額外操作到視圖集中魔慷。讓我們把之前的CourseEnrollView
視圖為一個自定義視圖集操作。編輯api/views.py
文件吊奢,并修改CourseViewSet
類:
from rest_framework.decorators import detail_route
class 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})
我們添加了一個自定義的enroll()
方法盖彭,它代表這個視圖集的一個額外操作。上面的代碼執(zhí)行以下任務:
- 我們使用框架的
detail_route
裝飾器页滚,指定這是在單個對象上執(zhí)行的操作召边。 - 裝飾器允許我們?yōu)椴僮魈砑幼远x屬性。我們指定這個視圖只允許POST方法裹驰,并設置了認證和權(quán)限類隧熙。
- 我們使用
self.get_object()
檢索Courses
對象。 - 我們把當前用戶添加到
students
多對多關(guān)系中幻林,并返回一個自定義的成功響應贞盯。
編輯api/urls.py
文件,移除以下URL沪饺,因為我們不再需要它:
url(r'^courses/(?P<pk>\d+)/enroll/$', views.CourseEnrollView.as_view(), name='course_enroll'),
然后編輯api/views.py
文件躏敢,移除CourseEnrollView
類。
現(xiàn)在整葡,報名參加課程的URL由路由自動生成件余。因為它使用操作名enroll
,所以URL保持不變。
12.1.11 創(chuàng)建自定義權(quán)限
我們希望學生可以訪問它們報名的課程內(nèi)容啼器。只有報名的學生才可以訪問課程內(nèi)容旬渠。最好的實現(xiàn)方式是使用一個自定義權(quán)限類。Django提供的BasePermission
類允許你定義以下方法:
-
has_permission()
:視圖級別的權(quán)限檢查 -
has_object_permission()
:實例級別的權(quán)限檢查
如果獲得訪問權(quán)限端壳,這些方法返回True
告丢,否則返回False
。在courses/api/
目錄中創(chuàng)建permissions.py
文件损谦,并添加以下代碼:
from rest_framework.permissions import BasePermission
class IsEnrolled(BasePermission):
def has_object_permission(self, request, view, obj):
return obj.students.filter(id=request.user.id).exists()
我們從BasePermission
類繼承岖免,并覆寫has_object_permission()
。我們檢查執(zhí)行請求的用戶是否存在Course
對象的students
關(guān)系中成翩。我們下一步會使用IsEnrolled
權(quán)限觅捆。
12.1.12 序列化課程內(nèi)容
我們需要序列化課程內(nèi)容。Content
模型包括一個通用外鍵麻敌,允許我們訪問關(guān)聯(lián)對象的不同內(nèi)容模型。但是掂摔,我們在上一章為所有內(nèi)容模型添加了通用的render()
方法术羔。我們可以使用這個方法為API提供渲染后的內(nèi)容。
編輯courses
應用的api/serializers.py
文件乙漓,并添加以下代碼:
from ..models import Content
class 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')
在這段代碼中级历,通過繼承REST Framework提供的RelatedField
序列化器字段和覆寫to_representation()
方法,我們定義了一個自定義字段叭披。我們?yōu)?code>Content模型定義了ContentSerializer
序列化器寥殖,并用自定義字段作為item
通用外鍵。
我們需要一個包括內(nèi)容的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')
讓我們創(chuàng)建一個模仿retrieve()
操作同诫,但是包括課程內(nèi)容的視圖粤策。編輯api/views.py
文件,并在CourseViewSet
類中添加以下方法:
from .permissions import IsEnrolled
from .serializers import CourseWithContentsSerializer
class 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)
這個方法執(zhí)行以下任務:
- 我們使用
detail_route
裝飾器指定該操作在單個對象上執(zhí)行误窖。 - 我們指定該操作只允許GET方法叮盘。
- 我們使用新的
CourseWithContentsSerializer
序列化器類,它包括渲染的課程內(nèi)容霹俺。 - 我們使用
IsAuthenticated
和自定義的IsEnrolled
權(quán)限柔吼。這樣可以確保只有報名的用戶可以訪問課程內(nèi)容。 - 我們使用存在的
retrieve()
操作返回課程對象丙唧。
在瀏覽器中打開http://127.0.0.1:8000/api/courses/1/contents/
愈魏。如果你用正確證書訪問視圖,你會看到課程的每個單元,包括渲染后的課程內(nèi)容的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"
}
]
}
你已經(jīng)構(gòu)建了一個簡單的API串塑,允許其它服務通過編程方式訪問course
應用。REST Framework還允許你用ModelViewSet
視圖集管理創(chuàng)建和編輯對象北苟。我們已經(jīng)學習了Django Rest Framework的主要部分桩匪,但你仍可以在這里進一步學習它的特性。
12.2 總結(jié)
在這一章中友鼻,你創(chuàng)建了一個RESTful API傻昙,可以讓其它服務與你的web應用交互。
額外的第十三章可以在這里下載彩扔。它教你如何使用uWSGI
和NGINX
構(gòu)建一個生產(chǎn)環(huán)境妆档。你還會學習如何實現(xiàn)一個自定義的中間件和創(chuàng)建自定義的管理命令。
你已經(jīng)到達了本書的結(jié)尾虫碉。恭喜你贾惦!你已經(jīng)學會了用Django構(gòu)建一個成功的web應用所需要的技巧。本書指導你完成開發(fā)實際項目敦捧,以及將Django與其它技術(shù)結(jié)合⌒氚澹現(xiàn)在你已經(jīng)準備好創(chuàng)建自己的Django項目,不管是一個簡單的原型還是一個大型的web應用兢卵。
祝你下一次Django冒險活動好運习瑰!