转载自:http://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/

Tutorial 5: Relationships & Hyperlinked APIs

At the moment relationships within our API are represented by using primary keys. In this part of the tutorial we'll improve the cohesion and discoverability of our API, by instead using hyperlinking for relationships.

Creating an endpoint for the root of our API

Right now we have endpoints for 'snippets' and 'users', but we don't have a single entry point to our API. To create one, we'll use a regular function-based view and the @api_view decorator we introduced earlier. In your snippets/views.py add:

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)
})

Two things should be noticed here. First, we're using REST framework's reverse function in order to return fully-qualified URLs; second, URL patterns are identified by convenience names that we will declare later on in our snippets/urls.py.

Creating an endpoint for the highlighted snippets

The other obvious thing that's still missing from our pastebin API is the code highlighting endpoints.

Unlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two styles of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint.

The other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance.

Instead of using a concrete generic view, we'll use the base class for representing instances, and create our own .get()method. In your snippets/views.py add:

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)

As usual we need to add the new views that we've created in to our URLconf. We'll add a url pattern for our new API root in snippets/urls.py:

url(r'^$', views.api_root),

And then add a url pattern for the snippet highlights:

url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),

Hyperlinking our API

Dealing with relationships between entities is one of the more challenging aspects of Web API design. There are a number of different ways that we might choose to represent a relationship:

  • Using primary keys.
  • Using hyperlinking between entities.
  • Using a unique identifying slug field on the related entity.
  • Using the default string representation of the related entity.
  • Nesting the related entity inside the parent representation.
  • Some other custom representation.

REST framework supports all of these styles, and can apply them across forward or reverse relationships, or apply them across custom managers such as generic foreign keys.

In this case we'd like to use a hyperlinked style between entities. In order to do so, we'll modify our serializers to extend HyperlinkedModelSerializer instead of the existing ModelSerializer.

The HyperlinkedModelSerializer has the following differences from ModelSerializer:

  • It does not include the id field by default.
  • It includes a url field, using HyperlinkedIdentityField.
  • Relationships use HyperlinkedRelatedField, instead of PrimaryKeyRelatedField.

We can easily re-write our existing serializers to use hyperlinking. In your snippets/serializers.py add:

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')

Notice that we've also added a new 'highlight' field. This field is of the same type as the url field, except that it points to the 'snippet-highlight' url pattern, instead of the 'snippet-detail' url pattern.

Because we've included format suffixed URLs such as '.json', we also need to indicate on the highlight field that any format suffixed hyperlinks it returns should use the '.html' suffix.

Making sure our URL patterns are named

If we're going to have a hyperlinked API, we need to make sure we name our URL patterns. Let's take a look at which URL patterns we need to name.

  • The root of our API refers to 'user-list' and 'snippet-list'.
  • Our snippet serializer includes a field that refers to 'snippet-highlight'.
  • Our user serializer includes a field that refers to 'snippet-detail'.
  • Our snippet and user serializers include 'url' fields that by default will refer to '{model_name}-detail', which in this case will be 'snippet-detail' and 'user-detail'.

After adding all those names into our URLconf, our final snippets/urls.py file should look like this:

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')),
]

Adding pagination

The list views for users and code snippets could end up returning quite a lot of instances, so really we'd like to make sure we paginate the results, and allow the API client to step through each of the individual pages.

We can change the default list style to use pagination, by modifying our tutorial/settings.py file slightly. Add the following setting:

REST_FRAMEWORK = {
'PAGE_SIZE': 10
}

Note that settings in REST framework are all namespaced into a single dictionary setting, named 'REST_FRAMEWORK', which helps keep them well separated from your other project settings.

We could also customize the pagination style if we needed too, but in this case we'll just stick with the default.

Browsing the API

If we open a browser and navigate to the browsable API, you'll find that you can now work your way around the API simply by following links.

You'll also be able to see the 'highlight' links on the snippet instances, that will take you to the highlighted code HTML representations.

In part 6 of the tutorial we'll look at how we can use ViewSets and Routers to reduce the amount of code we need to build our API.

Tutorial 5: Relationships & Hyperlinked APIs的更多相关文章

  1. 05_Tutorial 5: Relationships & Hyperlinked APIs 关系和超链接

    1.关系和超链接 0.文档 https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/ h ...

  2. Django REST framework 第五章 Relationships & Hyperlinked APIs

    到目前为止,API内部的关系是使用主键来代表的.在这篇教程中,我们将提高API的凝聚力和可发现性,通过在相互关系上使用超链接. Creating an endpoint for the root of ...

  3. 5,基于关系和超链接的 API

    Tutorial 5: Relationships & Hyperlinked APIs At the moment relationships within our API are repr ...

  4. django-rest-framework快速入门

    前言:第一次接触django-rest-framework是在实习的时候.当时也不懂,看到视图用类方法写的感觉很牛逼的样子.因为官网是英文的,这对我的学习还是有一点的阻力的,所以当时也没怎么学.真是太 ...

  5. django rest framework 详解

    Django REST framework 是用于构建Web API 的强大而灵活的工具包. 我们可能想使用REST框架的一些原因: Web浏览API对于开发人员来说是一个巨大的可用性. 认证策略包括 ...

  6. drf 教程

    1, 序列化 Serialization 创建一个新环境 在做其他事之前,我们会用virtualenv创建一个新的虚拟环境.这将确保我们的包配置与我们正在工作的其他项目完全隔离. virtualenv ...

  7. Hibernate quick start

    Preface Working with both Object-Oriented software and Relational Databases can be cumbersome and ti ...

  8. Apache Atlas

    atlas英 [ˈætləs] 阿特拉斯. 美 [ˈætləs] n.地图集;〈比喻〉身负重担的人 == Apache Atlas Version: 1.1.0 Last Published: 201 ...

  9. django restframework 简单总结

    官方文档:http://www.django-rest-framework.org/ model.py class Snippet(models.Model): created = models.Da ...

随机推荐

  1. Python常忘的基础知识

    0.目录 1.进制 1.1 各进制的表示 1.2 各进制的转换 2.字符 2.1 转义字符 2.2 原始字符串 3.类型 3.1 基本数据类型 3.2 type() 4.变量与运算符 4.1 值类型与 ...

  2. 分布式文件系统服务器FastDFS

    1. 什么是FastDFS FastDFS 是用 c 语言编写的一款开源的分布式文件系统.FastDFS 为互联网量身定制, 充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标, ...

  3. Django之form表单提交并验证

    1.提交的时候会报错 2. 需要在setting里面注释掉一句话,关闭跨站请求检查. 3. 注释掉以后,理论上就不报错了.可我还是卡壳了. 4. 通过在网上找方法,修复错误. 原因:表单action字 ...

  4. 【BZOJ4889】不勤劳的图书管理员(树套树)

    [BZOJ4889]不勤劳的图书管理员(树套树) 题面 又是权限题,烦死了 洛谷真好 题解 分开考虑每一次交换产生的贡献. 假设交换\((x,y)\) 检查\(x\)与\(y\)对于区间\([x+1, ...

  5. 【BZOJ4011】【HNOI2015】落忆枫音(动态规划)

    [BZOJ4011][HNOI2015]落忆枫音(动态规划) 题面 BZOJ 洛谷 Description 「恒逸,你相信灵魂的存在吗?」 郭恒逸和姚枫茜漫步在枫音乡的街道上.望着漫天飞舞的红枫,枫茜 ...

  6. [ACM][2018南京预赛]Magical Girl Haze

    一.题面 样例输入: 15 6 11 2 21 3 42 4 33 4 13 5 64 5 2 样例输出: 3 二.思路 关键词:分层BFS 考试时觉得题干意思很清晰——求可将k条边赋值为0的最短路. ...

  7. Python之旅:装饰器

    装饰器就是闭包函数的一种应用场景 一.为何要用装饰器 开放封闭原则:软件一旦上线后,就应该遵循开放封闭原则,即对修改源代码是封闭的,对功能的扩展是开放的 也就是说我们必须找到一种解决方案:能够在不修该 ...

  8. 04-树4. Root of AVL Tree-平衡查找树AVL树的实现

    对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是O(logN),而接近O(N),这样将大大减少对树的查找效率.一种解决办法就是要有一个称为平衡的附加的结构条件 ...

  9. gitlab配置自动同步

    如果需要同步到生产环境,请做额外处理,如自动化测试,测试通过再同步. <?php $project = trim($_GET['project']); if (empty($project)) ...

  10. 限制SSH远程登录用户仅能只读访问Linux中指定的目录

    资料参考:http://os.51cto.com/art/201703/534895.htm 背景需求: 在TOMCAT服务器上建立一个普通帐号log_user,只能查看TOMCAT日志,不能删改任何 ...