前面章节中我们创建的API中的关系都是通过使用主键来表示的。在本章节中,将改进API的内聚力和可发现性,而不是使用超链接来进行关系。
为API创建一个根路径
目前现有的路径有:snippets和users,但是我们的API没有一个入口点。我们将使用一个常规的基于函数的视图和我们前面介绍的@api_view
装饰器创建一个。在snipptes/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({
"user": reverse("user-list", request=request, format=format),
"snippets": reverse("snippet-list", request=request, format=format)
})
需要主可以的两点是:1.我们使用REST framework的reverse函数返回完全限定的URL;2.URL模型通过snippets/urls.py
中声明的遍历名称进行标识,后面将对其新增配置。
为高亮显示snippets创建路由
我们API中目前还缺少一个代码高亮的显示路径。
与其他API路径不同,这次只是需要HTML表示而不是JSON。REST框架提供了两种HTML渲染器,一种用于处理使用模板渲染的HTML,另一种用于处理预渲染的HTML。第二
渲染器是我们要用于次路径的渲染器。
创建代码高亮视图时需要考虑的另一件事是,我们没有可用的具体通用视图。我们不是返回对象实例,而是返回对象实例的属性。不是使用具体的通用视图,我们将使用基类来表示实例,并创建我们自己的.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
中的URLconf为新创建的视图添加路劲:
urlpatterns = [
...
# 根路径
path("", views.api_root, name="index"),
# 代码高亮
path("snippet/<int:pk>/highlight/", views.SnippetHighlight.as_view(), name="snippet-detail-highlight"),
]
超链接我们的API
处理好实体之间的关系式Web API设计中更具挑战性的方面。可以选择几种不同的方式来代表一种关系:
- 使用主键。
- 在实体之间使用超链接。
- 在相关实体上使用唯一的标识字段。
- 使用相关实体的默认字符串表示形式。
- 将相关实体嵌套在父表示中。
- 一些其他自定义表示。
REST框架支持这些所有的方式,并且可以将它们应用于正向或反向关系,也可以在诸如通用外键之类的自定义管理器上应用。
在这种情况下,我们希望在实体之间使用超链接方式。这样的话,我们需要修改我们的序列化器的代码来扩展HyperlinkedModelSerializer
而不是现有的ModelSerializer
。
HyperlinkedModelSerializer
和ModelSerializer
的区别: - 默认情况下不包括id字段。
- 它包含要一个url字段,使用
HyperlinkedIdentityField
。 关联关系使用HyperlinkedRelatedField
,而不是PrimaryKeyRelatedField
。
示例:
```python
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')
### 确保URL模式被命名
如果要使用超链接的API,那么需要确保为URL模式命名。
```python
# snippets/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = format_suffix_patterns([
path("", views.api_root),
path("snippets/", views.SnippetList.as_view(), name="snippet-list"),
path("snippet/<int:pk>/", views.SnippetDetail.as_view(), name="snippet-detail"),
path("snippet/<int:pk>/highlight/", views.SnippetHighlight.as_view(), name="snippet-detail-highlight"),
path("users/", views.UserList.as_view(), name="user-list"),
path("user/<int:pk>/", views.UserDetail.as_view(), name="user-detail"),
])
添加分页
列表视图页面最终可能会返回很多实例,如果希望对结果进行分页,并允许API客户端逐步浏览也每个页面。可以在tutorial/settings.py
稍微修改文件来更改默认列表样式以使用分页。添加设置如下:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}