書籍出處:https://www.packtpub.com/web-development/django-example
原做者:Antonio Meléhtml
(譯者注:第十二章,全書最後一章,終於到這章了。)前端
在上一章中,你構建了一個學生註冊系統和課程報名。你建立了用來展現課程內容的視圖以及如何使用Django的緩存框架。在這章中,你將學習如何作到如下幾點:python
你可能想要建立一個接口給其餘的服務來與你的web應用交互。經過構建一個API,你能夠容許第三方來消費信息以及程序化的操做你的應用程序。web
你能夠經過不少方法構成你的API,可是咱們最鼓勵你遵循REST原則。REST體系結構來自Representational State Transfer。RESTful API是基於資源的(resource-based)。你的模型表明資源和HTTP方法例如GET,POST,PUT,以及DELETE是被用來取回,建立,更新,以及刪除對象的。HTTP響應代碼也能夠在上下文中使用。不一樣的HTTP響應代碼的返回用來指示HTTP請求的結果,例如,2XX響應代碼用來表示成功,4XX表示錯誤,等等。shell
在RESTful API中最通用的交換數據是JSON和XML。咱們將要爲咱們的項目構建一個JSON序列化的REST API。咱們的API會提供如下功能:django
咱們能夠經過建立定製視圖從Django開始構建一個API。固然,有不少第三方的模塊能夠給你的項目簡單的建立一個API,其中最有名的就是Django Rest Framework。api
Django Rest Framework容許你爲你的項目方便的構建REST APIs。你能夠經過訪問 http://www.django-rest-framework.org 找到全部REST Framework信息。瀏覽器
打開shell而後經過如下命令安裝這個框架:緩存
pip install djangorestframework=3.2.3
編輯educa項目的settings.py文件,在INSTALLED_APPS設置中添加rest_framework來激活這個應用,以下所示:服務器
INSTALLED_APPS = ( # ... 'rest_framework', )
以後,添加以下代碼到settings.py文件中:
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' ] }
你可使用REST_FRAMEWORK設置爲你的API提供一個指定的配置。REST Framework提供了一個普遍的設置去配置默認的行爲。DEFAULT_PERMISSION_CLASSES配置指定了去讀取,建立,更新或者刪除對象的默認權限。咱們設置DjangoModelPermissionsOrAnonReadOnly做爲惟一的默認權限類。這個類依賴與Django的權限系統容許用戶去建立,更新,或者刪除對象,同時提供只讀的訪問給陌生人用戶。你會在以後學習更多關於權限的方面。
若是要找到一個完整的REST框架可用設置列表,你能夠訪問 http://www.django-rest-framework.org/api-guide/settings/ 。
設置好REST Framework以後,咱們須要指定咱們的數據將會如何序列化。輸出的數據必須被序列化成指定的格式,而且輸出的數據將會給進程去序列化。REST框架提供瞭如下類來給單個對象去構建序列化:
讓咱們構建咱們的第一個序列化器。在courses應用目錄下建立如下文件結構:
api/ __init__.py serializers.py
咱們將會在api目錄中構建全部的API功能爲了保持一切都有良好的組織。編輯serializeers.py文件,而後添加如下代碼:
from rest_framework import serializers from ..models import Subject class SubjectSerializer(serializers.ModelSerializer): class Meta: model = Subject fields = ('id', 'title', 'slug')
以上是給Subject模型使用的序列化器。序列化器以一種相似的方式被定義給Django
的From和ModelForm類。Meta類容許你去指定模型序列化以及給序列化包含的字段。全部的模型字段都會被包含若是你沒有設置一個fields屬性。
讓咱們嘗試咱們的序列化器。打開命令行經過`python manage.py shell*開始Django shell。運行如下代碼:
from courses.models import Subject from courses.api.serializers import SubjectSerializer subject = Subject.objects.latest('id') serializer = SubjectSerializer(subject) serializer.data
在上面的例子中,咱們拿到了一個Subject對象,建立了一個SubjectSerializer的實例,而且訪問序列化的數據。你會獲得如下輸出:
{'slug': 'music', 'id': 4, 'title': 'Music'}
如你所見,模型數據被轉換成了Python的數據類型。
在你在一個HTTP響應中返回序列化數據以前,這個序列化數據必須使用指定的格式進行渲染。一樣的,當你拿到一個HTTP請求,在你使用這個數據操做以前你必須解析傳入的數據而且反序列化這個數據。REST Framework包含渲染器和解析器來執行以上操做。
讓咱們看下如何解析傳入的數據。給予一個JSON字符串輸入,你可使用REST康佳提供的JSONParser類來轉變它成爲一個Python對象。在Python shell中執行如下代碼:
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響應。框架會查明經過的內容使用的是哪一種渲染器。它對響應進行檢查,根據請求的Accept頭去預判內容的類型。除此之外,渲染器能夠經過URL的格式後綴進行預判。舉個例子,訪問將會出發JSONRenderer爲了返回一個JSON響應。
回到shell中,而後執行如下代碼去從提供的序列化器例子中渲染serializer對象:
from rest_framework.renderers import JSONRenderer JSONRenderer().render(serializer.data)
你會看到如下輸出:
b'{"id":4,"title":"Music","slug":"music"}'
咱們使用JSONRenderer去渲染序列化數據爲JSON。默認的,REST Framework使用兩種不一樣的渲染器:JSONRenderer和BrowsableAPIRenderer。後者提供一個web接口能夠方便的瀏覽你的API。你能夠經過REST_FRAMEWORK設置的DEFAULT_RENDERER_CLASSES選項改變默認的渲染器類。
你能夠找到更多關於渲染器和解析器的信息經過訪問 http://www.django-rest-framework.org/api-guide/renderers/ 以及 http://www.django-rest- framework.org/api-guide/parsers/ 。
REST Framework自帶一組通用視圖和mixins,你能夠用來構建你本身的API。它們提供了獲取,建立,更新以及刪除模型對象的功能。你能夠看到全部REST Framework提供的通用mixins和視圖,經過訪問 http://www.django-rest-framework.org/api-guide/generic-views/ 。
讓咱們建立列表和詳情視圖去取回Subject對象們。在courses/api/目錄下建立一個新的文件並命名爲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參數給詳情視圖去取回對象。兩個視圖都有如下屬性:
讓咱們給咱們的視圖添加URL模式。在courses/api/目錄下建立新的文件並命名爲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')), ]
咱們給咱們的API URLs使用api命名空間。確保你的服務器已經經過命令python manange.py runserver
啓動。打開shell而後經過cURL獲取URL http://127.0.0.1:8000/api/subjects/ 以下所示:
$ curl http://127.0.0.1:8000/api/subjects/
你會獲取相似如下的響應:
[{"id":2,"title":"Mathematics","slug":"mathematics"},{"id":4,"title":"Music","slug":"music"},{"id":3,"title":"Physics","slug":"physics"},{"id":1,"title":"Programming","slug":"programming"}]
這個HTTP響應包含JSON格式的一個Subject對象列。若是你的操做系統沒有安裝過cURL,你可還可使用其餘的工具去發送定製HTTP請求例如一個瀏覽器擴展 Postman ,這個擴展你能夠在 https://www.getpostman.com 找到。
在你的瀏覽器中打開 http://127.0.0.1:8000/api/subjects/ 。你會看到以下所示的REST Framework的可瀏覽API:
這個HTML界面由BrowsableAPIRenderer渲染器提供。它展現告終果頭和內容而且容許執行請求。你還能夠在URL包含一個Subject對象的id來訪問該對象的API詳情視圖。在你的瀏覽器中打開 http://127.0.0.1:8000/api/subjects/1/ 。你將會看到一個單獨的渲染成JSON格式的Subject對象。
咱們將要給Course模型建立一個序列化。編輯api/serializers.py文件並添加如下代碼:
from ..models import Course class CourseSerializer(serializers.ModelSerializer): class Meta: model = Course fields = ('id', 'subject', 'title', 'slug', 'voerview', 'created', 'owner', 'modules')
讓咱們看下一個Course對象是如何被序列化的。打開shell,運行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)
你將會經過咱們包含在CourseSerializer中的字段獲取到一個JSON對象。你能夠看到modules管理器的被關聯對象唄序列化成一列關鍵值,以下所示:
"modules": [17, 18, 19, 20, 21, 22]
咱們想要包含個多的信息關於每個模塊,因此咱們須要序列化Module對象以及嵌套它們。修改api/serializers.py文件提供的代碼,使之看上去以下所示:
from rest_framework import serializers 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')
咱們給Module模型定義了一個ModuleSerializer去提供序列化。以後咱們添加一個modules屬性給CourseSerializer去嵌套ModuleSerializer序列化器。咱們設置many=True去代表咱們正在序列化多個對象。read_only參數代表這個字段是隻讀的而且不能夠被包含在任何輸入中去建立或者升級對象。
打開shell而且再次建立一個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." }, ... ]
你能夠找到更多關於序列化器的內容,經過訪問 http://www.django-rest-framework.org/api-guide/serializers/。
REST Framework提供一個APIView類,這個類基於Django的View類構建API功能。APIView類與View在使用REST Framework的定製Request以及Response對象時不一樣,而且操做APIException例外的返回合適的HTTP響應。它還有一個內建的驗證和認證系統去管理視圖的訪問。
咱們將要建立一個視圖給用戶去對課程進行報名。編輯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視圖操縱用戶對課程進行報名。以上代碼解釋以下:
編輯api/urls.py文件而且給CourseEnrollView視圖添加如下URL模式:
url(r'^courses/(?P<pk>\d+)/enroll/$', views.CourseEnrollView.as_view(), name='course_enroll'),
理論上,咱們如今能夠執行一個POST請求去給當前用戶對一個課程進行報名。可是,咱們須要辨認這個用戶而且阻止爲認證的用戶來訪問這個視圖。讓咱們看下API認證和權限是如何工做的。
REST Framework提供認證類去辨別用戶執行的請求。若是認證成功,這個框架會在request.user中設置認證的User對象。若是沒有用戶被認證,一個Django的AnonymousUser實例會被代替。
REST Framework提供如下認證後臺:
你能夠建立一個經過繼承REST Framework提供的BaseAuthentication類的子類以及重寫authenticate()方法來構建一個定製的認證後臺。
你能夠在每一個視圖的基礎上設置認證,或者經過DEFAULT_AUTHENTICATION_CLASSES設置爲全局認證。
認證只能失敗用戶正在執行的請求。它沒法容許或者組織視圖的訪問。你必須使用權限去限制視圖的訪問。
你能夠找到關於認證的全部信息,經過訪問 http://www.django-rest- framework.org/api-guide/authentication/ 。
讓咱們給咱們的視圖添加BasicAuthentication。編輯courses應用的api/views.py文件,而後給CourseEnrollView添加一個authentication_classes屬性,以下所示:
from rest_framework.authentication import BasicAuthentication class CourseEnrollView(APIView): authentication_classes = (BasicAuthentication,) # ...
用戶將會被設置在HTTP請求中的Authorization頭裏面的證書進行識別。
REST Framework包含一個權限系統去限制視圖的訪問。一些REST Framework的內置權限以下所示:
若是用戶沒有權限,他們一般會得到如下某個HTTP錯誤:
你能夠得到更多的關於權限的信息,經過訪問 http://www.django-rest- framework.org/api-guide/permissions/ 。
編輯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權限。這個權限將會組織陌生用戶訪問這個視圖。如今,咱們能夠之sing一個POST請求給咱們的新的API方法。
確保開發服務器正在運行。打開shell而後運行如下命令:
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 code,由於咱們沒有認證過。讓咱們帶上咱們的一個用戶進行下基礎認證。運行如下命令:
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}
你能夠額訪問管理站點而後檢查到上面命令中的用戶已經完成了課程的報名。
ViewSets容許你去定義你的API的交互而且讓REST Framework經過一個Router對象動態的構建URLs。經過使用視圖設置,你能夠避免給多個視圖重複編寫相同的邏輯。視圖設置包含典型的建立,獲取,更新,刪除選項操做,它們是 list(),create(),retrieve(),update(),partial_update()以及destroy()。
讓咱們給Course模型建立一個視圖設置。編輯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文件而且給咱們的視圖設置建立一個路由,以下所示:
from django.conf.urls import url, include from rest_framework import routers from . import views router = routers.DefaultRouter() router.register('courses', views.CourseViewSet) urlpatterns = [ # ... url(r'^', include(router.urls)), ]
咱們建立兩個一個DefaultRouter對象而且經過courses前綴註冊了咱們的視圖設置。這個路由負責給咱們的視圖動態的生成URLs。
在你的瀏覽器中打開 http://127.0.0.1:8000/api/ 。你會看到路由排列除了全部的視圖設置在它的基礎URL中,以下圖所示:
你能夠訪問 http://127.0.0.1:8000/api/courses/ 去獲取課程的列表。
你能夠學習到跟多關於視圖設置的內容,經過訪問 http://www.django-rest-framework.org/api-guide/viewsets/ 。你也能夠找到更多關於路由的信息,經過訪問 http://www.django-rest-framework.org/api-guide/routers/ 。
你能夠給視圖設置添加額外的操做。讓咱們修改咱們以前的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()方法至關於給這個視圖設置的一個額外的操做。以上的代碼解釋以下:
編輯api/urls.py文件並移除如下URL,由於咱們再也不須要它們:
url(r'^courses/(?P<pk>[\d]+)/enroll/$', views.CourseEnrollView.as_view(), name='course_enroll'),
以後編輯api/views.py文件而且移除CourseEnrollView類。
這個用來在課程中報名的URL如今已是由路由動態的生成。這個URL保持不變,由於它使用咱們的操做名enroll動態的進行構建。
咱們想要學生能夠訪問他們報名過的課程的內容。只有在這個課程中報名過的學生才能訪問這個課程的內容。最好的方法就是經過一個定製的權限類。Django提供了一個BasePermission類容許你去定製如下功能:
以上方法會返回True來容許訪問,相反就會返回False。在courses/api/中建立一個新的文件並命名爲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()。咱們檢查執行請求的用戶是否存在Course對象的students關係。咱們下一步將要使用IsEnrolled權限。
咱們須要序列化課程內容。Content模型包含一個通用的外鍵容許咱們去關聯不一樣的內容模型對象。然而,咱們給上一章中給全部的內容模型添加了一個公用的render()方法。咱們可使用這個方法去提供渲染過的內容給咱們的API。
編輯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提供的RealtedField序列化器字段定義了一個定製字段而且重寫了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')
讓咱們建立一個視圖來模仿retrieve()操做的行爲可是包含課程內容。編輯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)
以上的方法解釋以下:
在你的瀏覽器中打開 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" } ] }
你已經構建了一個簡單的API容許其餘服務器來程序化的訪問課程應用。REST Framework還容許你經過ModelViewSet視圖設置去管理建立以及編輯對象。咱們已經覆蓋了Django Rest Framework的主要部分,可是你能夠找到該框架更多的特性,經過查看它的文檔,地址在 http://www.django-rest-framework.org/ 。
在這章中,你建立了一個RESTful API給其餘的服務器去與你的web應用交互。
一個額外的章節第十三章,Going Live須要在線下載:https://www. packtpub.com/sites/default/files/downloads/Django_By_Example_ GoingLive.pdf 。第十三章將會教你如何使用uWSGI以及NGINX去構建一個生產環境。你還將學習到如何去導入一個定製中間件以及建立定製管理命令。
你已經到達這本書的結尾。恭喜你!你已經學習到了經過Django構建一個成功的web應用所需的技能。這本書指導你經過其餘的技術與Django集合去開發了幾個現實生活能用到的項目。如今你已經準備好去建立你本身的Django項目了,不管是一個簡單的樣品仍是一個一個強大的wen應用。
祝你下一次Django的冒險好運!
完結撒花!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2016年12月7日開始翻譯第一章到今天2017年3月29日終於全書翻譯完成!
對我而言真的是一次很是大膽的嘗試,但終於堅持下來了!!!!!!!!
要相信本身作的到!
請容許我多打幾個感嘆號表達個人心情!
感謝全部支持和鼓勵的人!
精校工做也正在不斷的進行中,請你們原諒一開始的渣翻!
其實還有不少不少想說的話,可是不知道說什麼好!就這樣吧!