當前位置:
首頁 > 知識 > Django編寫RESTful API——ViewSets和Routers

Django編寫RESTful API——ViewSets和Routers


前言

在本系列的文章中,我在第一篇和第二篇文章中寫的編寫Django視圖時,使用的都是基於函數的方法,並且每個視圖函數之前都會加一個django-rest-framework帶的裝飾器@api_view。然後在第三篇文章,我們就開始把基於函數的視圖改成了基於類的視圖,然後發現這樣做視圖部分減少了很多代碼量。

在這一篇文章中,我要介紹的是另一種基於類的視圖的寫法,它的抽象程度更高,也可以說是代碼量又減少了。OK,廢話不多說,先進入主題~



使用ViewSets重構視圖

先介紹一下這個ViewSets。ViewSets,翻譯過來可以說是視圖集,也就是幾個視圖的集合。

拿本項目為例子,我們之前查看所有用戶列表就要寫一個視圖類UserList,並在urls.py中為其設置一個模式然後as_view使用它,然後要看單個用戶的詳情頁就要再寫一個UserDetail視圖類並再在添加一個url模式。同時注意到這兩個視圖類都是繼承的generics.XXXAPIView。而使用ViewSets我們就可以把UserList和UserDetail合併成UserViewSet視圖類,並且繼承的類改為viewsets.ReadOnlyModelViewSet,這樣就是一個視圖集了。

還是有點懵逼?沒事,下面看看代碼。編輯snippets/view.py,導入viewsets並使用UserViewSet來替換掉UserList和UserDetail:

Django編寫RESTful API——ViewSets和Routers

這裡面的queryset和serializer_class的值還是和原來一樣。因為關於User的API都是只讀的,所以我們繼承了一個ReadOnlyModelViewSet類,這樣就把原先的兩個視圖類集合起來了。原本類裡面的:

Django編寫RESTful API——ViewSets和Routers

這部分屬於重複代碼,所以通過視圖集來實現視圖類我們的代碼量確實減少了,更加簡潔。

ViewSet類與View類其實幾乎是相同的,但提供的是read或update這些操作,而不是get或put 等HTTP動作。同時,ViewSet為我們提供了默認的URL結構, 使得我們能更專註於API本身。

上面這段話呢,是官方文檔裡面說的,想就這樣看看就算了來理解也行,不過如果我們看一下源碼也許能理解的更好。因為我用的是PyCharm,所以查看源碼很方便,按住CTRL鍵然後滑鼠點擊一下就會自動跳轉了,首先查看一下ReadOnlyModelViewSet,發現它是這樣的:

Django編寫RESTful API——ViewSets和Routers

發現原來有用到之前說的mixins,所以剛才才說ViewSet類與View類其實幾乎是相同的。但是這裡多了一個GenericViewSet類是新的內容,繼續CTRL點擊查看其代碼,發現它內部只是一個pass然後就沒有其他的操作了,但是可以繼續查看其父類ViewSetMixin的源碼來了解ViewSets,然後就可以看到這個ViewSetMixin其實重寫了as_view方法:

Django編寫RESTful API——ViewSets和Routers

我們平時使用視圖類的時候,編寫urls.py時,就一個XXX.as_view(),現在使用ViewSets,需要傳入參數,大概像下面這樣的:

Django編寫RESTful API——ViewSets和Routers

之後url就配置好了,也就是上面說的ViewSet為我們提供了默認的URL結構。當然了,這個還不是完整的url模式,稍後補全。

剛才把User的兩個視圖類合併成視圖集了,那麼Snippet的幾個視圖類操作上也是差不多的。用視圖集SnippetViewSet代替SnippetList, SnippetDetail 和 SnippetHighlight這三個視圖類:

Django編寫RESTful API——ViewSets和Routers

因為查看highlight不像其他動作那樣,django-rest-framework並沒有替我們封裝好,所以我們需要自己添加這個額外的動作,要記得在方法前面加上裝飾器@detail_route,這個裝飾器就是用來創建自定義的動作,當然我們的自定義動作不可以是create/update/delete這些標準的,否則會有衝突。

還有一點,用@detail_route裝飾器定義的動作默認是GET請求,需要其他的請求方式可以傳入methods參數給這個裝飾器。同樣的,默認情況下,自定義操作的URL取決於方法名稱本身。如果要更改url應該構造的方式,可以將url_path作為decorator的關鍵字參數。

最後還要注意繼承的類是ModelViewSet和剛才的也有點不同,為什麼換成這個,也可以看看源碼能略知一二:

Django編寫RESTful API——ViewSets和Routers



將ViewSets明確的綁定到URL

根據上面所說的,每個視圖集的url模式都需要我們在as_view中傳入參數,把snippets/urls.py的代碼換成下面的:

Django編寫RESTful API——ViewSets和Routers

OK,到了這裡對視圖的改造已經完成了,可以啟動伺服器測試一下,我們的項目功能還是和之前的一樣的。



使用Routers

不過看到urls.py的代碼,我們可能會發現一個問題,就是我們的視圖類代碼簡潔了變少了,但是url.py的代碼量好像多了啊,要綁定那麼多動作,這樣算起來好像也沒多大提升?

確實是這樣。但是我們這可是在用python開發啊,當然是能短則短了,沒錯,django-rest-framework的作者也是這麼想的,所以我們又有現成的輪子可以使用了。這個輪子就是本文的另一個主角——Routers。用起來也是簡單粗暴,重寫urls.py:

Django編寫RESTful API——ViewSets和Routers

這樣就搞定了,代碼少了很多,連原來用來設置後綴的下面這行代碼都不需要了。

Django編寫RESTful API——ViewSets和Routers

而且這個DefaultRouter 類還會自動幫我們創建API根視圖,也就是說view.py中的api_root方法也可以刪除掉了。

額...這個Routers幫我們做的事情真是有點多啊。。不過這也就是我為什麼在文章的前言裡面說使用ViewSets會比原本的視圖更抽象的原因。

拿過來用是會了,但是這裡面發生了什麼我們完全不知道啊,比如說API後綴去哪了?上面我們寫的:

Django編寫RESTful API——ViewSets和Routers

這些綁定全都自動生成了?這些確實都是DefaultRouter 幫我們做好了,怎麼做的,我們還是可以看一下源碼了解一下大概的過程。首先就是register方法,我們綁定了那麼多動作它兩行就搞定了,查看它的源碼,發現它是BaseRouter類下的一個方法:

Django編寫RESTful API——ViewSets和Routers

改方法根據傳進來的參數生成url端點,也就是/snippets和/users,然後存到registry列表中。並且這個類的最後是一個可以當屬性用的方法urls,而這個方法裡面又調用了get_urls()來生成所有的url模式,當然這個get_urls()被子類SimpleRouter和子子類DefaultRouter重寫了。SimpleRouter中的get_urls()實現了生成是5個url模式,也就是原本的:

Django編寫RESTful API——ViewSets和Routers

而DefaultRouter中的get_urls()中則生成了api_root的url模式,同時還為這些url模式加了格式後綴,所以我們自己不會用到format_suffix_patterns這個東西。



總結

當然了,並不一定要使用ViewSets的視圖代替View,兩者各有好處ViewSets節省了很多代碼並且url模式也不用我們自己設置了,但是也會帶來一些不確定性,自動化的效果有時候可能和你預想的不太一樣,所以想要選擇哪種方法看你自己喜歡。

文章來自博客園


中公優就業IT培訓,總有你想學的:http://xue.ujiuye.com

勤工儉學計劃,0元學IT!

http://www.ujiuye.com/zt/qgjx/?wt.bd=lsh11tt

找工作太難?我們來幫你一舉拿下!

http://www.ujiuye.com/zt/jycj/?wt.bd=lsh11tt

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT優就業 的精彩文章:

深度解析C++拷貝構造函數
JS小福利——實時更新的頁面小時鐘
設計模式——裝飾者模式
四季之後,我能記住的,只有你的名字
心理測試|直覺哪根最辣?解析你潛藏的個性!

TAG:IT優就業 |