Tastypie

第一次寫 Web API 就上手
by 信傑
Outline
● 為什麼要用 Web API ?
● Tastypie 能幫我們作什麼?
● 如何開始寫 Tastypie?
● 如何強化你的 Web API?
● 如何調校你的 Tastypie?
● Tastypie 還可以怎樣改?
為什麼要用 Web API ?
● 回顧一下 Request 週期
url
Request

view
model
Response
template
為什麼要用 Web API ? (cont'd)
● 那如果系統要在不同平台上使用呢?

?
為什麼要用 Web API ? (cont'd)

這個專案需要更
高級的 Package
為什麼要用 Web API ? (cont'd)
● 所以我們使用『Tastypie』來製作 Web API
Tastypie 能幫我們作什麼?
● 首先必須先介紹什麼是 RESTful?

註:http://zh.wikipedia.org/wiki/REST
Tastypie 能幫我們作什麼?(cont’d)
● Tastypie 就是幫你完成 django - model 到
Web api 中間的轉換
● 以 django.contrib.auth 的 Group, User,
Permissi...
Tastypie 能幫我們作什麼?(cont’d)
user_set

user_permissions

permissions
groups
group_set

user_set
如何開始寫 Tastypie?
1. pip install django django-tastypie mysqlpython mimeparse
2. django-admin.py startproject myApp
3. cd ./...
如何開始寫 Tastypie?(cont’d)
● vim ./myApi/api/resources.py
from tastypie.resources import ModelResource
from django.contrib.au...
如何開始寫 Tastypie?(cont’d)
● vim ./myApp/myApi/urls.py
from django.conf.urls import patterns, include, url
from api.resources...
如何開始寫 Tastypie?(cont’d)
● vim ./myApp/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':...
如何開始寫 Tastypie?(cont’d)
● vim ./myApp/urls.py
from django.conf.urls import patterns, include, url
urlpatterns = patterns('...
如何開始寫 Tastypie?(cont’d)
1. python manage.py syncdb
2. python manage.py runserver
3. GET http://localhost:8000/api/user/ or...
如何開始寫 Tastypie?(cont’d)
如何開始寫 Tastypie?(cont’d)

什麼?
Web API 完成了?

是的,你的第一個
Web API 完成了
如何強化你的 Web API?
● 先多增加兩個 API: api/resources.py
from django.contrib.auth.models import Group, User, Permission
…
class Grou...
如何強化你的 Web API?(cont’d)
● 再新增/修改 url:api/urls.py
from api.resources import UserModelResource,
GroupModelResource, Permissi...
如何強化你的 Web API?(cont’d)
● 現在已經又多兩了 Web API 了http:
//localhost:8000/api/group/ & http://localhost:
8000/api/permission/
如何強化你的 Web API?(cont’d)
● 疑?總覺的哪裡怪怪的
● 多了很多不想被看到的欄位資料
● 表單之間的關聯都沒看到
● 繼續對 resources.py 作努力
如何強化你的 Web API?(cont’d)
from tastypie import fields
class UserModelResource(ModelResource):
groups = fields.ToManyField('a...
如何強化你的 Web API?(cont’d)
class GroupModelResource(ModelResource):
permissions = fields.ToManyField('api.resources.
Permissi...
如何強化你的 Web API?(cont’d)
如何強化你的 Web API?(cont’d)
● 現在已經可以隱藏部分欄位,以及顯示相關聯
的資料了
● 那 API 除了查詢,新增、修改與刪除功能勒?
● 繼續修改 resources.py
如何強化你的 Web API?(cont’d)
…
from tastypie.authorization import Authorization
class UserModelResource(ModelResource):
groups ...
如何強化你的 Web API?(cont’d)
class GroupModelResource(ModelResource):
permissions = fields.ToManyField('api.resources.Permissio...
如何強化你的 Web API?(cont’d)
● 現在可以完整的測試 CRUD 了
如何調校你的 Tastypie?
● 如果對 Tastypie 預設的樣板不滿意的話,那
就覆寫(修改)它吧
如何調校你的 Tastypie?(cont’d)
from tastypie.resources import ModelResource, ALL_WITH_RELATIONS
from tastypie.utils.urls import ...
如何調校你的 Tastypie?(cont’d)
class GroupModelResource(ModelResource):
...
class Meta:
…
detail_uri_name = 'name'
filtering = {...
如何調校你的 Tastypie?(cont’d)
● 試試看加個參數:
http://localhost:8000/api/user/
?groups__name=a

● 這樣查詢好像有點 low
● 那改 URL 如何?
如何調校你的 Tastypie?(cont’d)
class UserModelResource(ModelResource):
def base_urls(self):
return [
url(r"^(?P<resource_name>%s...
如何調校你的 Tastypie?(cont’d)
● 似乎還差一點點
○ GET http://localhost:8000/api/group/a/user/ :
1.

"meta": {

2.

"limit": 10,

3.

"n...
如何調校你的 Tastypie?(cont’d)
class BaseModelResource(ModelResource):
pass
…
class UserModelResource(BaseModelResource):
…
clas...
如何調校你的 Tastypie?(cont’d)
class BaseModelResource(ModelResource):
def get_list(self, request, **kwargs):
base_bundle = self...
如何調校你的 Tastypie?(cont’d)
class BaseModelResource(ModelResource):
…
def get_resource_list_uri(self, **kwargs):
if self._met...
如何調校你的 Tastypie?(cont’d)
● 這樣就修正完畢了
○ GET http://localhost:8000/api/group/a/user/ :
1.

"meta": {

2.

"limit": 10,

3.

"...
Tastypie 還可以怎樣改?
● 再介紹一個核心資料『bundle』
● 『bundle』貫串了 Tastypie 的資料處理過程,
其中包含了
○ data :
資料
○ obj :
model 物件
○ request : 就 requ...
Tastypie 還可以怎樣改?(cont’d)

hydrate
data

obj

dehydrate
bundle
Tastypie 還可以怎樣改?(cont’d)
bundle

bundle

full_hydrate

full_dehydrate

hydrate

field.dehydrate

hydrate_%s

dehydrate_%s
...
Tastypie 還可以怎樣改?(cont’d)
Request

URL
dispatch
(list/detail)

[get/post/put/delete]_[list/detail]

hydrate

Response

dehy...
Tastypie 還可以怎樣改?(cont’d)
● 你想要的功能,找出最適合的位置(function),
覆寫它吧!
註:對不起,我只會這麼多而已。
Upcoming SlideShare
Loading in …5
×

Tastypie

573 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
573
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
13
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Tastypie

  1. 1. Tastypie 第一次寫 Web API 就上手 by 信傑
  2. 2. Outline ● 為什麼要用 Web API ? ● Tastypie 能幫我們作什麼? ● 如何開始寫 Tastypie? ● 如何強化你的 Web API? ● 如何調校你的 Tastypie? ● Tastypie 還可以怎樣改?
  3. 3. 為什麼要用 Web API ? ● 回顧一下 Request 週期 url Request view model Response template
  4. 4. 為什麼要用 Web API ? (cont'd) ● 那如果系統要在不同平台上使用呢? ?
  5. 5. 為什麼要用 Web API ? (cont'd) 這個專案需要更 高級的 Package
  6. 6. 為什麼要用 Web API ? (cont'd) ● 所以我們使用『Tastypie』來製作 Web API
  7. 7. Tastypie 能幫我們作什麼? ● 首先必須先介紹什麼是 RESTful? 註:http://zh.wikipedia.org/wiki/REST
  8. 8. Tastypie 能幫我們作什麼?(cont’d) ● Tastypie 就是幫你完成 django - model 到 Web api 中間的轉換 ● 以 django.contrib.auth 的 Group, User, Permission 作範例
  9. 9. Tastypie 能幫我們作什麼?(cont’d) user_set user_permissions permissions groups group_set user_set
  10. 10. 如何開始寫 Tastypie? 1. pip install django django-tastypie mysqlpython mimeparse 2. django-admin.py startproject myApp 3. cd ./myApp 4. python manage.py startapp myApi 5. mkdir ./myApi/api && touch . /myApi/api/__init__.py 6. vim ./myApi/api/resources.py
  11. 11. 如何開始寫 Tastypie?(cont’d) ● vim ./myApi/api/resources.py from tastypie.resources import ModelResource from django.contrib.auth.models import Group, User class UserModelResource(ModelResource): class Meta: queryset = User.objects.all() resource_name = 'user' allowed_methods = ['get']
  12. 12. 如何開始寫 Tastypie?(cont’d) ● vim ./myApp/myApi/urls.py from django.conf.urls import patterns, include, url from api.resources import UserModelResource urlpatterns = patterns('', (r'', include(UserModelResource().urls)), )
  13. 13. 如何開始寫 Tastypie?(cont’d) ● vim ./myApp/settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'myApp', 'USER': 'root', 'PASSWORD': 'root', 'HOST': '127.0.0.1', 'PORT': '', } } … INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', ... 'tastypie', myApi, )
  14. 14. 如何開始寫 Tastypie?(cont’d) ● vim ./myApp/urls.py from django.conf.urls import patterns, include, url urlpatterns = patterns('', … (r'^api/', include('myApi.urls')), )
  15. 15. 如何開始寫 Tastypie?(cont’d) 1. python manage.py syncdb 2. python manage.py runserver 3. GET http://localhost:8000/api/user/ or http: //localhost:8000/api/user/?format=json
  16. 16. 如何開始寫 Tastypie?(cont’d)
  17. 17. 如何開始寫 Tastypie?(cont’d) 什麼? Web API 完成了? 是的,你的第一個 Web API 完成了
  18. 18. 如何強化你的 Web API? ● 先多增加兩個 API: api/resources.py from django.contrib.auth.models import Group, User, Permission … class GroupModelResource(ModelResource): class Meta: queryset = Group.objects.all() resource_name = 'group' allowed_methods = ['get'] class PermissionModelResource(ModelResource): class Meta: queryset = Permission.objects.all() resource_name = 'permission' allowed_methods = ['get']
  19. 19. 如何強化你的 Web API?(cont’d) ● 再新增/修改 url:api/urls.py from api.resources import UserModelResource, GroupModelResource, PermissionModelResource … urlpatterns = patterns('', (r'', include(UserModelResource().urls)), (r'', include(GroupModelResource().urls)), (r'', include(PermissionModelResource().urls)), )
  20. 20. 如何強化你的 Web API?(cont’d) ● 現在已經又多兩了 Web API 了http: //localhost:8000/api/group/ & http://localhost: 8000/api/permission/
  21. 21. 如何強化你的 Web API?(cont’d) ● 疑?總覺的哪裡怪怪的 ● 多了很多不想被看到的欄位資料 ● 表單之間的關聯都沒看到 ● 繼續對 resources.py 作努力
  22. 22. 如何強化你的 Web API?(cont’d) from tastypie import fields class UserModelResource(ModelResource): groups = fields.ToManyField('api.resources.GroupModelResource', 'groups') permissions = fields.ToManyField('api.resources.PermissionModelResource', 'user_permissions') class Meta: queryset = User.objects.all() resource_name = 'user' allowed_methods = ['get'] #detail_allowed_methods = ['get'] #fields = ['username', 'first_name', 'last_name', 'last_login'] excludes = ['id', 'is_active', 'date_joined', 'password', 'is_staff', 'is_superuser']
  23. 23. 如何強化你的 Web API?(cont’d) class GroupModelResource(ModelResource): permissions = fields.ToManyField('api.resources. PermissionModelResource', 'permissions') #users = fields.ToManyField('api.resources.UserModelResource', 'user_set') users = fields.ToManyField(UserModelResource, 'user_set') class Meta: queryset = Group.objects.all() resource_name = 'group' allowed_methods = ['get'] #detail_allowed_methods = ['get']
  24. 24. 如何強化你的 Web API?(cont’d)
  25. 25. 如何強化你的 Web API?(cont’d) ● 現在已經可以隱藏部分欄位,以及顯示相關聯 的資料了 ● 那 API 除了查詢,新增、修改與刪除功能勒? ● 繼續修改 resources.py
  26. 26. 如何強化你的 Web API?(cont’d) … from tastypie.authorization import Authorization class UserModelResource(ModelResource): groups = fields.ToManyField('api.resources.GroupModelResource', 'groups', null=True) permissions = fields.ToManyField('api.resources.PermissionModelResource', 'user_permissions', null=True) class Meta: ... #allowed_methods = ['get'] list_allowed_methods = ['get', 'post'] detail_allowed_methods = ['get', 'put'] ... always_return_data = True #authentication = Authentication() # BasicAuthentication, ApiKeyAuthentication authorization = Authorization() # ReadOnlyAuthorization, DjangoAuthorization
  27. 27. 如何強化你的 Web API?(cont’d) class GroupModelResource(ModelResource): permissions = fields.ToManyField('api.resources.PermissionModelResource', 'permissions', null=True) users = fields.ToManyField('api.resources.UserModelResource', 'user_set', null=True) class Meta: ... list_allowed_methods = ['get', 'post'] detail_allowed_methods = ['get', 'put', 'delete'] always_return_data = True authorization = Authorization()
  28. 28. 如何強化你的 Web API?(cont’d) ● 現在可以完整的測試 CRUD 了
  29. 29. 如何調校你的 Tastypie? ● 如果對 Tastypie 預設的樣板不滿意的話,那 就覆寫(修改)它吧
  30. 30. 如何調校你的 Tastypie?(cont’d) from tastypie.resources import ModelResource, ALL_WITH_RELATIONS from tastypie.utils.urls import trailing_slash from django.conf.urls import url ... class UserModelResource(ModelResource): … class Meta: ... detail_uri_name = 'username' filtering = { 'groups': ALL_WITH_RELATIONS, }
  31. 31. 如何調校你的 Tastypie?(cont’d) class GroupModelResource(ModelResource): ... class Meta: … detail_uri_name = 'name' filtering = { 'name': 'exact', }
  32. 32. 如何調校你的 Tastypie?(cont’d) ● 試試看加個參數: http://localhost:8000/api/user/ ?groups__name=a ● 這樣查詢好像有點 low ● 那改 URL 如何?
  33. 33. 如何調校你的 Tastypie?(cont’d) class UserModelResource(ModelResource): def base_urls(self): return [ url(r"^(?P<resource_name>%s)%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list'), name="api_dispatch_list"), url(r"^(?P<resource_name>%s)/(?P<%s>w[w/-]*)%s$" % (self._meta.resource_name, self._meta.detail_uri_name, trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), url(r"^group/(?P<groups__name>%s)/(?P<resource_name>%s)%s$" % (r'[w]{,80}', self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list'), name="api_dispatch_list"), url(r"^group/(?P<groups__name>%s)/(?P<resource_name>%s)/(?P<%s>w[w/-]*)%s$" % (r'[w]{,80}', self._meta.resource_name, self._meta.detail_uri_name, trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), ]
  34. 34. 如何調校你的 Tastypie?(cont’d) ● 似乎還差一點點 ○ GET http://localhost:8000/api/group/a/user/ : 1. "meta": { 2. "limit": 10, 3. "next": "/api/user/?limit=10&offset=10", 4. "offset": 0, 5. "previous": null, 6. "total_count": 13 7. } ● 需要對 get_list 作點修正,同樣 vim resources.py
  35. 35. 如何調校你的 Tastypie?(cont’d) class BaseModelResource(ModelResource): pass … class UserModelResource(BaseModelResource): … class GroupModelResource(BaseModelResource): … class PermissionModelResource(BaseModelResource): ...
  36. 36. 如何調校你的 Tastypie?(cont’d) class BaseModelResource(ModelResource): def get_list(self, request, **kwargs): base_bundle = self.build_bundle(request=request) objects = self.obj_get_list(bundle=base_bundle, **self.remove_api_resource_names(kwargs)) sorted_objects = self.apply_sorting(objects, options=request.GET) paginator = self._meta.paginator_class(request.GET, sorted_objects, 原程式修改這邊 resource_uri=self.get_resource_list_uri(**kwargs), limit=self._meta.limit, max_limit=self._meta.max_limit, collection_name=self._meta.collection_name) to_be_serialized = paginator.page() bundles = [] for obj in to_be_serialized[self._meta.collection_name]: bundle = self.build_bundle(obj=obj, request=request) bundles.append(self.full_dehydrate(bundle, for_list=True)) to_be_serialized[self._meta.collection_name] = bundles to_be_serialized = self.alter_list_data_to_serialize(request, to_be_serialized) return self.create_response(request, to_be_serialized)
  37. 37. 如何調校你的 Tastypie?(cont’d) class BaseModelResource(ModelResource): … def get_resource_list_uri(self, **kwargs): if self._meta.api_name is not None: kwargs['api_name'] = self._meta.api_name try: return self._build_reverse_url("api_dispatch_list", kwargs=kwargs) except Exception: return None
  38. 38. 如何調校你的 Tastypie?(cont’d) ● 這樣就修正完畢了 ○ GET http://localhost:8000/api/group/a/user/ : 1. "meta": { 2. "limit": 10, 3. "next": "/api/group/a/user/?limit=10&offset=10", 4. "offset": 0, 5. "previous": null, 6. "total_count": 13 7. }
  39. 39. Tastypie 還可以怎樣改? ● 再介紹一個核心資料『bundle』 ● 『bundle』貫串了 Tastypie 的資料處理過程, 其中包含了 ○ data : 資料 ○ obj : model 物件 ○ request : 就 request
  40. 40. Tastypie 還可以怎樣改?(cont’d) hydrate data obj dehydrate bundle
  41. 41. Tastypie 還可以怎樣改?(cont’d) bundle bundle full_hydrate full_dehydrate hydrate field.dehydrate hydrate_%s dehydrate_%s field.hydrate dehydrate hydrate bundle dehydrate bundle
  42. 42. Tastypie 還可以怎樣改?(cont’d) Request URL dispatch (list/detail) [get/post/put/delete]_[list/detail] hydrate Response dehydrate
  43. 43. Tastypie 還可以怎樣改?(cont’d) ● 你想要的功能,找出最適合的位置(function), 覆寫它吧!
  44. 44. 註:對不起,我只會這麼多而已。

×