這篇主要是針對於個人目前學習django rest framework的一些小小心得,在開發django而言,想要撰寫restful api,是有幾個套件可以選擇的

主要而言是這兩個,個人是學django rest framework,tastypie個人沒啥碰所以就不做啥比較了,當然你也可以不屑使用上面這兩個,小弟有看過使用requests來實作api的 :)

大致上這篇會用下列的順序介紹

  • core part
  • serializer
  • generic api
  • url router
  • some situation may bother you

core part

個人覺得這套主要核心整個圍繞在serializer上,其他的有class based views的相關api,api通常會跟permissionauthentication有所關聯,最後如果想要用比較generic way的方式,就要用到viewsetrouter

這邊rest framework的quick start個人覺得做了一個很簡單上手的示範,讓你先了解一些基本概念,serializer的基本使用方法,如果有看他source code,可以看到他的概念就是從django form,field那些過來的,所以會有很多類似的東西,至於serializer比較深的東西,下一個段落再來多說明。

quick start 後面也提到class based view的使用方式,不過他是從function based view帶到class based view,個人比較偏好class based view,可讀性更好,假如你一個function based view可接受很多http method,這樣裏面code就一定會參雜各種method的相對應code,很可能你裏面就會有向下面這樣

1
2
3
4
5
6
7

def (request, *arg, **kwargs):
if request.method == 'GET':
pass
elif request.method == 'POST':
pass

沒有說那種一定好一定壞,就看客官的個人喜好囉~~

再來requestresponse在restframework都有經過額外的包裝(包裝django的response和request)這邊比較沒啥要注意的。反而是authenticationpermission比較值得注意,也就是對於API進行一些存取權限的控管。有個地方需要注意的是

1
2
3
4
5
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,) authentication_classes = (SessionAuthentication, BasicAuthentication)

permission是裡面所有的permission都過了,這個request才可以執行,authentication是只要裏面有一個成功通過,那就可以執行了。

不信請看,rest framework源碼片斷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
) # the process for checking authentication
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return

最後的core part,就是viewset和router了,這部份就在url router那邊再多做說明。

serializer

serizlier跟django的Form使用起來很像,但是這不代表它是繼承於django的form喔,有興趣的看源碼,用serializer的目的,個人是覺得把表單驗證的邏輯(舉凡參數驗證也可)從api view切開,這樣也不會讓api裏面的程式碼過於複雜。

一般而言大多數情況應該都是使用modelserializer,的確針對於CRUD方面確實方便,但是有時候就是會遇到當你create這個model時,會有和model對不上的欄位,進而造成錯誤發生,或是很難使用,拿個最簡單的例子,創造一個使用者,通常會需要一個email,password,password2,但是使用者model並不會有password2,畢竟那只是確認使用者密碼是不是一致。

對於這種情形,我是另外寫一個serializer專門為創造使用者,而且也不是用ModelSerializer,只是一般的serializer,那記得要define create的method,假如你是要用在generic viewset的create的這地方。

另外使用modelserializer會遇到的一種情況是,今天你想要客製化回傳的資料,比如今天你的user model裏面有一個欄位是mugshot(ImageField),那個一般情況UserSerializer.data,那麼回傳格式通常會是希望是大概如下

1
2
3
4
{
"email": "aa@test.com",
"mugshot": "http://xxx.com.tw/media/.../" # url 位址
}

但是往往天不從人願,預設可不是回傳url位址,像這種情況我目前知道的算比較OK的解法有兩種

第1種

就是使用SerializerMethodField,基本上就是建立一個readonly的field,使用方法文檔說明了很清楚,這邊我就不多說明~~

第2種

就是overwride serializer的to_representationmethod,這個我是看源碼去理解出來的邪門歪道? 不過這邊也只是跟你講講也可以用這樣的方法 :p

再來就是文檔的地方也有說,使用serializer時,帶入partial這個參數是可以直接partiali update或是其他的東東,這是一個不錯用的東西~~

1
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

最後其實剛剛上述的對於creation的用途另外寫一個專用的serializer,你也可以不要這樣寫,就全都寫在同樣的serializer上,用上面的userserializer繼續舉例:

1
2
3
4
5
6
7
8
9
大专栏  django rest framework 小小心得pan class="keyword">class UserSerializer(serializers.ModelSerializer):

	password2 = serializer.CharField(required=False)

	class Meta:

		model = User
fields = ('username', 'email')

注意~如果你password2的Field不加required的話,由於modelserializer的to_representation會去檢查這個field是否存在於這個model,這時就會爽快的爆掉啦~~

不過別以為任務就這樣結束了,根據你這個serializer的用途,接下來你就要自己去overwrite,createorupdate這兩個方法。會不會覺得很簡單? 其實說真的是不難(前提你知道rest framework背後幫你搞什麼…,但是我一直在想這樣寫就變成有好多邏輯都混在這個serializer裡面~

目前而言,我並不清楚哪種寫法才是最好的,畢竟我碰這套framework沒有說很久,也不是核心開發者,我只是提供稍微比較tricky的方式來達到各種目的。

generic api

generic api這是我比較最近接觸的東西,老實講一開始學這套我還真的只用rest framework的APIView打天下,api的參數驗證也自己來,其實這也好像沒啥不行xxd,只是這套framework既然提供了serializer和generic api view,就一定有他的用處,所以最近碰了一些,打算寫點東西來記錄。

首先來講講GenericViewSet和GenericAPIView,不~ 其實應該這樣看,在restframework的ViewSet其實都是繼承於APIView,所以看到GenericViewSet,可以知道其實這個是繼承GenericAPIView,那麼到底這兩者差在哪? 一樣來看看源碼~ 比較仔細閱讀文檔,不如鑽研源碼搭配文檔還比較有效率,個人是這樣認為拉! 每個人都有自己的習慣,所以不一定要照我的方法,找到屬於自己最有效率的方法才是比較重要的,話題拉回來,下面是源碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
"""
pass class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
"""
pass

看出什麼了嗎?他們都多了ViewSetMixin,如果懶的看源碼理解~ 其實可看他程式碼裏面的註解寫的簡單易懂,下面是註解片段

1
2
3
4
5
6
7
Overrides `.as_view()` so that it takes an `actions` keyword that performs
the binding of HTTP methods to actions on the Resource. For example, to create a concrete view binding the 'GET' and 'POST' methods
to the 'list' and 'create' actions... view = MyViewSet.as_view({'get': 'list', 'post': 'create'})

應該不需要多解釋了吧? 再來主要需要理解的是 APIView和GenericAPIView這兩個做了什麼,這邊就不再貼源碼,直接做個大綱的介紹,應該說個人的理解 :P

由於GenericAPIView是繼承APIView,所以就先來看看APIView實際上到底做了什麼,若你很常用class based view,其實這你應該常碰到,這個我本人也沒深入研究(掩面,但是大致上是做了authentication和permission以及dispatch(url router相關),還有一些和browserable api render相關等等的處理,這個就不多說了,畢竟源碼我沒什麼讀。

GenericAPIView比起剛剛那些多了

  • get_queryset
  • get_object
  • get_serializer
  • filter_queryset
  • ….

很明顯開始跟serializer之間關聯性越來越高,因此ModelViewSet也是繼承這個去實作額外的動作 :) GenericAPIView有幾個地方值得注意,因為根據你的case,你應該會很容易發現到,你會想要客製化某些功能,因為你的case並沒有那麼generic~~

最常會overwrite的function應該是get_serializer_class,這通常是CRUD中,你特別寫了C的serializer,R也一個,甚至U也一個,所以這時候需要判斷不同http method或是action去使用不同的serializer。

  • get_queryset
  • get_object

這兩個你也有可能會想覆寫~

最後一個心得,關於這邊的使用方式,與其去讀文檔,直接來讀source code更容易理解,給各位客官參考

url router

Routers,這個東東,老實講我並沒有覺得好用,而且綁得很死,Routers是跟ModelViewSet綁在一起的,她做的事情其實也只是幫你自動產生你常寫的urlpattern。

所以所以,我個人目前不知道這個有很好用? 仔細想想,今天假如你要用一個nested router的效果,但是你的第二層,卻只是單單onetoone,這樣url後面還需要帶參數(id)嗎?

ex.

1
2
3
http://example.com/api/users/5/profile/<pk>/  # 後面還需要?
http://example.com/api/users/5/profile/ # 應該只要這樣就好了吧

這個問題,是我在用nested router套件時發現的,沒錯套件,你沒看錯,內建是沒有支援nested的….

因此,我個人推薦urlpattern這邊還是自己動手寫吧,自由度相對大很多,而且別人要trace你的code,也變得比較容易,要不然你都用register,沒辦法一眼看出,那個url是對應到哪個view~

最後如果有人知道Router其實可以變得好用,也請教教我xxd

some situation may bother you

這邊阿~~~ 其實前面在講各個觀念時,也大概都提了一些可能會遇到的卡點,所以這邊大概是小小結論我仍然覺得疑惑的地方,

第一點,serializer到底是只要純負責關於CRUD的處理判斷邏輯就好? 還是說對於api的參數處理,我都應該要實作一個serializer去對應? 這個是指有些api並沒有對model做CRUD,但是卻也有相對應的動作,比如要驗證手機時,獲取驗證碼(GET),驗證你拿到的驗證碼(POST? PATCH?),這些動作也一定會有參數需要驗證吧,但是我目前還不知道把邏輯放在哪邊比較好~~ 也不知道有在用rest framework的各位寫程式時,有沒有一樣的煩惱

第二點,就是該用哪種http method去對應動作,通常是對於非CRUD,可能會猶豫一下該用哪種http method,url的配置要怎麼配置,前面router說不想用也是這個原因,router把你綁死,萬一你遇到奇怪神奇的要求,你就好笑了,但是這個還好,看各家公司想要怎麼做吧~~

第三點,想要直接全域客製化api回傳格式,這是最近我遇到的要求,解法也在這邊提供一下,根據文檔,自己寫一個APIException handler,處理成你想要的格式即可。

最後,就是這套framework是需要時間熟悉的xd 想要一看就上手恐怕有點難,除非你本來django就熟到爆炸,那這套framework你應該會很快上手,畢竟有一些概念時來自django的。

tags: python restful api django

django rest framework 小小心得的更多相关文章

  1. 使用django rest framework

    django 刚接触,想做一些restful api , google了一下,发现有现成的框架.Django REST framework. 对使用做下记录: 安装 从http://django-re ...

  2. 利用 Django REST framework 编写 RESTful API

    利用 Django REST framework 编写 RESTful API Updateat 2015/12/3: 增加 filter 最近在玩 Django,不得不说 rest_framewor ...

  3. django rest framework 入门

    django rest framework 入门1-序列化 Serialization 分类: Python 2013-01-22 22:24 11528人阅读 评论(0) 收藏 举报 djangop ...

  4. django rest framework

    Django-Rest-Framework 教程: 4. 验证和权限 作者: Desmond Chen, 发布日期: 2014-06-01, 修改日期: 2014-06-02 到目前为止, 我们的AP ...

  5. django rest framework csrf failed csrf token missing or incorrect

    django rest framework csrf failed csrf token missing or incorrect REST_FRAMEWORK = { 'DEFAULT_AUTHEN ...

  6. Django REST Framework学习——Android使用REST方法访问Diango

    本文更应该叫做Android如何模拟浏览器访问Django服务器后台. 环境为: Android通过HttpClient访问服务器,从Django中获取json数据,解析显示在UI界面上. 问题为: ...

  7. Django form模块使用心得

    最近用Django 写了一个网站,现在来分享一下对Django form 的一些心得. 一,创建一个表单 创建一个Form表单有两种方式: 第一种方式是继承于forms.Form,的一个子类,通过在f ...

  8. 用Django Rest Framework和AngularJS开始你的项目

    Reference: http://blog.csdn.net/seele52/article/details/14105445 译序:虽然本文号称是"hello world式的教程&quo ...

  9. Django REST framework使用ViewSets的自定义路由实现过程

    在Django中使用基于类的视图(ClassView),类中所定义的方法名称与Http的请求方法相对应,才能基于路由将请求分发(dispatch)到ClassView中的方法进行处理,而Django ...

随机推荐

  1. 关于域名转发proxy_pass

    在配置nginx的时候,有一个需求,访问m.XXX.com的时候,需要实际访问www.YYY.com/m,并且域名不能发生变化. 达成这个需求有两种做法: 第一种就是301跳转,使用rewrite来跳 ...

  2. 给rar文件加个自定义头

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  3. 吴裕雄--天生自然MySQL学习笔记:MySQL 元数据

    你可能想知道MySQL以下三种信息: 查询结果信息: SELECT, UPDATE 或 DELETE语句影响的记录数. 数据库和数据表的信息: 包含了数据库及数据表的结构信息. MySQL服务器信息: ...

  4. 吴裕雄--天生自然 JAVASCRIPT开发学习:计时事件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 吴裕雄--天生自然 JAVASCRIPT开发学习: DOM

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. Html4.0.1 标签使用笔记

    1.lang=zh,en有什么用? 告诉搜索引擎爬虫,网站是关于什么内容的,优先显示网站排名.一般竞价排名,根据百度搜索引擎,需要签订关键词协议,首页第一个竞价排名大概是30-50元/条,竞价排名范围 ...

  7. Android 公告新闻消息资讯之垂直滚动效果

    垂直滚动新闻栏的实现原理: 就是一个自定义的LinearLayout,并且textView能够循环垂直滚动,而且条目可以点击,显示区域最多显示2个条目,并且还有交替的属性垂直移动的动画效果,通过线程来 ...

  8. modbus 指令16 $10 的格式

    { //写多个请求 01(从设备)10(功能码) 00 77(起始地址) 00 01(寄存器数) 02(字节数) 05 55(写的数据) 6F B8(CRC) //写多个返回 01(从设备) 10(功 ...

  9. PHP时间戳常用转换

    //设置中国时区 date_default_timezone_set('PRC'); //今天的时间搓 $today_start = strtotime(date('Y-m-d',time()).' ...

  10. 单机版solr的搭建

    1.1. Solr的环境 Solr是java开发. 需要安装jdk. 安装环境Linux. 需要安装Tomcat. 1.2. 搭建步骤 第一步:把solr 的压缩包上传到Linux系统 第二步:解压s ...