书籍出处: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日终于全书翻译完成!
对我而言真的是一次很是大胆的尝试,但终于坚持下来了!!!!!!!!
要相信本身作的到!
请容许我多打几个感叹号表达个人心情!
感谢全部支持和鼓励的人!
精校工做也正在不断的进行中,请你们原谅一开始的渣翻!
其实还有不少不少想说的话,可是不知道说什么好!就这样吧!