目前我们使用主键来表示模型之间的关系。在本章,我们将提高API的凝聚性和可读性。
为我们API的根节点创建URL
之前我们给snippets
和users
创建了URL接口,但我们没有一个根节点的URL。
在此我们创建一个简单的,基于函数的views,并为它加上@api_view
装饰器,修改snippets/views.py
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框架中的
reverse
方法来返回完全符合规则的url - url参数将会与我们之后在
snippets/urls
中定义的相同
编写snippets/urls.py
url(r'^$', views.api_root),
为高亮代码创建URL
接下来我们需要为高亮代码提供接口,和其它的接口不同,这个接口我们需要展现渲染好的HTML页面,而不是JSON。
REST框架给我们提供了两种HTML展现形式,一种是使用模板渲染,一种是使用已经提前渲染好的HTML,在此我们使用第二种。
另外,我们需要考虑当创建代码高亮的view时,我们没有现成的类来继承,因为我们不是返回对象,而是返回对象的一个属性,我们需要重写父类的get
方法。
编辑snippets/views.py
:
from rest_framework import renderers
from rest_framework.response import Response
class SnippetHighlight(generics.GenericAPIView):
queryset = Snippet.objects.all()
renderer_classes = (renderers.StaticHTMLRenderer,)
def get(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
编写snippets/urls.py
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
API之间使用超链接
在Web API中处理各个API之间的关系是一件非常头疼的事情,通常有以下方法表示关系:
- 使用主键
- 在API之间使用超链接
- 在关联API之间使用唯一字段表示
- 在关联API之间使用默认字符串表示
- 将一个API嵌套在另一个API类中
- 其它
REST框架支持上述所有方法,并且可以应用于正向、反向关系或类似外键这类自定义管理项。
在这里我们使用超链接来处理之间的关系,因此我们需要修改serializers
,使用HyperlinkedModelSerializer
替代原先的ModelSerializer
:
- 默认不包含主键
- 使用
HyperlinkedRelatedField
时,需要在Meta
子类的fields
中包含``urls`字段 - 使用
HyperlinkedRelatedField
来代替PrimaryKeyRelatedField
表示关系
编辑snippets/serializers.py
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ('url', 'id', 'highlight', 'owner',
'title', 'code', 'linenos', 'language', 'style')
class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
class Meta:
model = User
fields = ('url', 'id', 'username', 'snippets')
这里在SnippetSerializer
中新增了一个highlight
属性,这个属性和url
字段类型相同,区别在于它指向的是snippet-highlight
而非snippet-detail
另外,由于我们有.json
格式的后缀,我们需要指定highlight
字段使用.html
来返回相应的格式
确保URL都被命名
在此之前我们创建了一些url参数,在此罗列:
- 根节点指向了
user-list
和snippet-list
-
snippet serializer
包含了一个指向snippet-highlight
的url的字段 -
user serializer
包含了指向snippet-detail
的url的字段 -
snippet serializer
和user serializer
都包含了url
字段,这个字段默认指向{model_name}-detail
,这里分别是snippet-detail
和user-detail
编辑snippet/urls.py
from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
# API endpoints
urlpatterns = format_suffix_patterns([
url(r'^$', views.api_root),
url(r'^snippets/$',
views.SnippetList.as_view(),
name='snippet-list'),
url(r'^snippets/(?P<pk>[0-9]+)/$',
views.SnippetDetail.as_view(),
name='snippet-detail'),
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$',
views.SnippetHighlight.as_view(),
name='snippet-highlight'),
url(r'^users/$',
views.UserList.as_view(),
name='user-list'),
url(r'^users/(?P<pk>[0-9]+)/$',
views.UserDetail.as_view(),
name='user-detail')
])
# Login and logout views for the browsable API
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
添加分页
后面可能会有很多个数据产生,我们需要对返回结果进行分页,修改tutorial/settings.py
REST_FRAMEWORK = {
'PAGE_SIZE': 10
}
注意,所有关于REST框架的settings都在一个叫做REST_FRAMEWORK
的字典中,这帮助我们与其他的settings分离开来。
关于
本人是初学Django REST framework,Django REST framework 学习纪要系列文章是我从官网文档学习后的初步消化成果,如有错误,欢迎指正。
学习用代码Github仓库:shelmingsong/django_rest_framework
本文参考的官网文档:Tutorial 5: Relationships & Hyperlinked APIs
博客更新地址
- 宋明耀的博客 [ 第一时间更新 ]
- 知乎专栏 Python Cookbook
- 简书 流月0的文章