DRF嚮導之Relationships和Hyperlinked APIs

Tutorial 5: Relationships & Hyperlinked APIs

src

到目前爲止,在我們的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<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),



3. API超鏈接化

在Web API設計中,處理實體間關係是一個有挑戰性的工作。我們有許多方式來表示關係:

  • 使用主鍵;
  • 使用超鏈接;
  • 使用相關實體唯一標識的字段;
  • 使用相關實體的默認字符串表示;
  • 在父級表示中嵌入子級實體;
  • 其他自定義的表示。

REST framework支持所有這些方式,包括正向或者反向的關係,或者將其應用到自定義的管理類中,例如泛型外鍵。

在這部分,我們使用超鏈接方式。爲了做到這一點,我們需要在序列化器中用 HyperlinkedModelSerializer 來替代之前的 ModelSerializer.

HyperlinkedModelSerializerModelSerializer 有如下的區別:

  • 缺省狀態下不包含 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<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 += 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中,以便於其他配置區分。

如有必要,你也可以自定義分頁的方式,這裏不再贅述。



6. 瀏覽api

如果我們打開一個瀏覽器並導航到可瀏覽的api,您將發現您現在可以通過以下鏈接繞過api。
您還可以在代碼段實例上看到“highlight”鏈接,這些鏈接將帶您進入highlighted代碼html表示。
在本教程的第6部分中,我們將介紹如何使用視圖集和路由器來減少構建api所需的代碼量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章