1 | #!/usr/bin/env python |
adaptor
直接看代码吧
1 | # -*- coding: utf-8 -*- |
merge-sort
理解不深入的缘故,每次写算法都要对着例子抄。。
1 | def mergesort(seq): |
这些都是吃饭的家伙。。
django-rest-framework-5
到目前为止,在我们的API中关系(relationship)还是通过主键来表示的。在这部分的教程中,我们将用超链接方式来表示关系,从而提升API的统一性和可发现性。
##1. 为API根创建一个endpoint
到目前为止,我们已经有了’snippets’和’users’的endpoint, 但是我们还没有为我们的API单独创立一个端点入口。我们可以用常规的基于函数的view和之前介绍的 @api_view 修饰符来创建。
from rest_framework import renderers
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
@api_view((‘GET’,))
def api_root(request, format=None):
return Response({
‘users’: reverse(‘user-list’, request=request, format=format),
‘snippets’: reverse(‘snippet-list’, request=request, format=format)
})
请注意,我们用 REST framework 的 reverse 函数来返回完全合规的URLs.
##2. 为高亮的Snippet创建一个endpoint
我们目前还没有为支持代码高亮的Snippet创建一个endpoints.
与之前的API endpoints不同, 我们将直接使用HTML呈现,而非JSON。在 REST framework中有两种风格的HTML render, 一种使用模板来处理HTML,一种则使用预先处理的方式。在这里我们使用后者。
另一个需要我们考虑的是,对于高亮代码的view并没有具体的泛型view可以直接利用。我们将只返回实例的一个属性而不是对象实例本身。
没有具体泛型view的支持,我们使用基类来表示实例,并创建我们自己的 .get() 方法。在你的 snippets.views 中增加:
from rest_framework import renderers
from rest_framework.response import Response
class SnippetHighlight(generics.SingleObjectAPIView):
model = Snippet
renderer_classes = (renderers.StaticHTMLRenderer,)
def get(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
和以往一样,我们需要为新的view增加新的URLconf,如下增加urlpatterns:
url(r’^$’,’api_root’),
还需要为代码高亮增加一个urlpatterns:
url(r’^snippets/(?P
##3. API超链接化
在Web API设计中,处理实体间关系是一个有挑战性的工作。我们有许多方式来表示关系:
使用主键;
使用超链接;
使用相关实体唯一标识的字段;
使用相关实体的默认字符串表示;
在父级表示中嵌入子级实体;
其他自定义的表示。
REST framework支持所有这些方式,包括正向或者反向的关系,或者将其应用到自定义的管理类中,例如泛型外键。
在这部分,我们使用超链接方式。为了做到这一点,我们需要在序列化器中用 HyperlinkedModelSerializer 来替代之前的 ModelSerializer.
HyperlinkedModelSerializer 与 ModelSerializer 有如下的区别:
缺省状态下不包含 pk 字段;
具有一个 url 字段,即HyperlinkedIdentityField类型.
用HyperlinkedRelatedField表示关系,而非PrimaryKeyRelatedField.
我们可以很方便的改写现有代码来使用超连接方式:
class SnippetSerializer(serializers.HyperlinkedModelSerializer): owner = serializers.Field(source=’owner.username’) highlight = serializers.HyperlinkedIdentityField(view_name=’snippet-highlight’, format=’html’)
class Meta:
model = models.Snippet
fields = (‘url’, ‘highlight’, ‘owner’,
‘title’, ‘code’, ‘linenos’, ‘language’, ‘style’)
class UserSerializer(serializers.HyperlinkedModelSerializer): snippets = serializers.HyperlinkedRelatedField(many=True, view_name=’snippet-detail’)
class Meta:
model = User
fields = (‘url’, ‘username’, ‘snippets’)
注意:我们也增加了一个新的 ‘highlight’ 字段。该字段与 url 字段相同类型。不过它指向了 ‘snippet-highlight’的 url pattern, 而非’snippet-detail’ 的url pattern.
因为我们已经有一个 ‘.json’的后缀,为了更好的表明highlight字段链接的区别,使用一个 ‘.html’ 的后缀。
##4. 正确使用URL patterns
如果要使用超链接API,就必须确保正确的命名和使用 URL patterns. 我们来看看我们需要命名的 URL patterns:
指向 ‘user-list’ 和 ‘snippet-list’ 的API根.
snippet的序列化器,包括一个 ‘snippet-highlight’字段.
user序列化器,包含一个 ‘snippet-detail’字段.
snippet 和user的序列化器,包含 ‘url’ 字段(会缺省指向’snippet-detail’ 和 ‘user-detail’.
一番工作之后,最终的 ‘urls.py’ 文件应该如下所示:
API endpoints
urlpatterns = format_suffix_patterns(patterns(‘snippets.views’,
url(r’^$’, ‘api_root’),
url(r’^snippets/$’,
views.SnippetList.as_view(),
name=’snippet-list’),
url(r’^snippets/(?P
views.SnippetDetail.as_view(),
name=’snippet-detail’),
url(r’^snippets/(?P
views.SnippetHighlight.as_view(),
name=’snippet-highlight’),
url(r’^users/$’,
views.UserList.as_view(),
name=’user-list’),
url(r’^users/(?P
views.UserDetail.as_view(),
name=’user-detail’)
))
Login and logout views for the browsable API
urlpatterns += patterns(‘’,
url(r’^api-auth/‘, include(‘rest_framework.urls’,
namespace=’rest_framework’)),
)
##5. 添加分页
列表view有时会返回大量的实例结果,所以我们应该把结果分页显示,以便用户使用。
通过在 settings.py 中添加如下配置,我们就能在结果列表中增加分页的功能:
REST_FRAMEWORK ={‘PAGINATE_BY’:10}
请注意REST framework的所有配置信息都是存放在一个叫做 ‘REST_FRAMEWORK’的dictionary中,以便于其他配置区分。
如有必要,你也可以自定义分页的方式,这里不再赘述。
django-rest-framework-tutorial-4
drf框架教程4(djangorestframework)
写在前面
在外包的这段日子,不知如何描述滋味,虽然没有网络可以说限制了工作时间逛网页这种,但是自我感觉收获满足不了自己。是时候重新出发了。
工作当中有用到drf框架,在csdn中找到了还不错的中文翻译文档,受益匪浅。想着自己也做一部分翻译的工作。如有错误之处,请多多指教。
额外说明
目前版本为 3.6.3
认证和权限
目前为止,我们的API对谁能够编辑或者删除snippet(代码片段)还没有任何限制。我们将增加一些扩展功能来确保以下:
- snippets总关联一个创建者
- 只有认证后的用户才能创建一个snippets
- 只有创建者才能更新或者删除snippet
- 非认证的请求只拥有只读的权限
对model做一些修改,增加一个表示创建者,另外增加一个用来存储代码中的HTML高亮。
1 | # snippets/models.py |
另外 我们需要确保模型保存的时候,我们能够生成高亮的字段,这里使用pygments代码高亮库。
1 | from pygments.lexers import get_lexer_by_name |
为用户模型增加endpoints
现在我们有一些用户了,我们最好也把用户增加到API上,创建一个新的序列化脚本serializers.py
1 | # snippets/serializers.py |
因为snippets和user是反向关联,所以在使用ModelSerializers时不会缺省加入,因此需要显示加入。
我们还需要创建一些对用户呈现而言的views,最好使用只读的view,所以使用ListAPIView和RetrieveAPIView泛型类Views。
1 | # snippets/views.py |
确保导入了UserSerializers类
1 | from snippets.serializers import UserSerializer |
修改url
1 | url(r'^users/$', views.UserList.as_view()), |
snippets与users关联
现在,如果我们创建一个code snippet,还没有方法指定其创建者。User并没有作为序列化内容的一部分发送,而是作为request的一个属性。
这里的处理方法是重载snippet view中的.pre_save()方法,它可以让我们处理request中隐式的信息。
在SnippetList和SnippetDetail的view类中,都需要添加如下的方法:
1 | def perform_create(self, serializer): |
更新序列器
现在snippets已经和创建者关联起来了,我们接下来还需要更新SnippetSerializer,在其定义中增加一个新的字段:
1 | owner = serializers.ReadOnlyField(source='owner.username') |
Note: 确定你在嵌入类Meta的字段列表中也加入了’owner’。
这个字段所做的十分有趣。source参数表明增加一个新字段,可以指定序列化实例任何属性。它可以采用如上的点式表示(dotted notation),这时他可以直接遍历到指定的属性。在Django’s template中使用时,也可以采用类似的方式。
我们增加字段是一个无类型Field类,而我们之前的字段都是有类型的,例如CharField,BooleanFieldetc… 无类型字段总是只读的,它们只用在序列化表示中,而在反序列化时(修改model)不被使用。
给views增加必需的权限
现在代码片段 snippets 已经关联了用户,我们需要确保只有认证用户才能增、删、改snippets.
REST framework 包括许多权限类可用于view的控制。这里我们使用IsAuthenticatedOrReadOnly, 它可确保认证的request获取read-write权限,而非认证的request只有read-only 权限.
现需要在views模块中增加 import。
from rest_framework import permissions
然后需要在SnippetList和SnippetDetailview类中都增加如下属性:
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
可视化API增加登陆
如果你打开浏览器,访问可浏览API,你会发现只有登录后才能创建新的snippet了。
我们可以编辑URLconf来增加一个登录view。首先增加新的import:
from django.conf.urls import include
然后,在文件末尾增加一个pattern来为browsable API增加 login 和 logout views.
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
具体的,r’^api-auth/‘部分可以用任何你想用的URL来替代。这里唯一的限制就是 urls 必须使用’rest_framework’命名空间。
现在如果你打开浏览器,刷新页面会看到页面右上方的 ‘Login’ 链接。如果你用之前的用户登录后,你就又可以创建 snippets了。
一旦你创建了一些snippets,当导航至’/users/‘时,你会看到在每个user的snippets字段都包含了一系列snippet的pk。
对象级权限
我们希望任何人都可以浏览snippets,但只有创建snippet的用户才能编辑或删除它。
为了实现这个需求,我们需要创建定制的权限(custom permission)。
在 snippets 应用中,创建一个新文件:permissions.py
1 | from rest_framework import permissions |
现在我们可以为snippet实例增加定制权限了,需要编辑SnippetDetail 类的permission_classes属性:
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
别忘了import 这个IsOwnerOrReadOnly类。
from snippets.permissions import IsOwnerOrReadOnly
现在打开浏览器,你可以看见 ‘DELETE’ 和 ‘PUT’ 动作只会出现在那些你的登录用户创建的snippet页面上了.
通过API验证
我们已经有了一系列的权限,如果我们需要编辑任何snippet,我们需要认证我们的request。因为我们还没有建立任何authentication classes, 所以目前是默认的SessionAuthentication和BasicAuthentication在起作用。
当我们通过Web浏览器与API互动时,我们登录后、然后浏览器session可以为所有的request提供所需的验证。
如果我们使用程序访问这些API,我们则需要显式的为每个request提供认证凭证(authentication credentials)。
如果我们试图未认证就创建一个snippet,将得到错误如下:
1 | http POST http://127.0.0.1:8000/snippets/ code="print 123" |
如果我们带着用户名和密码来请求时则可以成功创建:
1 | http -a tom:password123 POST http://127.0.0.1:8000/snippets/ code="print 789" |
我们已经为我们的Web API创建了相当细粒度的权限控制和相应的系统用户。
在教程第5部分part 5,我们将把所有的内容串联起来,为我们的高亮代码片段创建HTML节点,并利用系统内的超链接关联来提升API的一致性表现。