关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
虽然是初次接触tastypie,不过前前后后我也仔细研读tastypie的帮助文档。并在实际开发项目中使用了1个多月,有所体悟,执笔记录。哦,正确来说是敲键盘记录。
tastypie是django的第三方库,可以轻松实现RESTful风格的API接口。
若你不知道什么是RESTful,可以先看看下面两篇文章。否则你可能不知道我在说什么。
目前tastypie更新到0.14.0版。不过这个版本有个bug,会提示“AttributeError: class Meta has no attribute 'object_class'.”错误。建议使用0.13.3版
pip install django-tastypie==0.13.3
Resource(资源)是RESTful基本概念,tastypie提供两种Resource类:Resource和ModelResource。
由于RESTful一般都是针对数据操作,所以我建议尽可能使用ModelResource。
ModelResource是基于Django的Model快速创建相应的资源。我们可以很方便使用tastypie提供的方法等。如果用Resource类完全自己定义十分费劲。
使用ModelResource,我们一般只需要设置Meta。具体设置可参考tastypie的文档。
一般Meta需要设置如下信息:
#coding:utf-8 from tastypie.resources import ModelResource from tastypie.authorization import Authorization from django.contrib.auth.models import User class UserResource(ModelResource): class Meta: resource_name = 'user' # 名称 queryset = User.objects.all() # 数据集 # 只显示哪些字段 fields = ['username', 'email',] # 允许的请求方式 list_allowed_methods = ['get', 'post'] detail_allowed_methods = ['get', 'patch'] # 权限 authorization = Authorization()
大致作用已经写在注释中,具体详细用法查官方文档即可。你可能会问Authentication、validation为什么没写,因为这两个是我在使用tastypie过程中,用起来不是很流畅的东西。
尤其是我采用测试驱动的方式开发,这些体会比较明显。
为了更好让大家充分理解这些东西,讲这些之前先给大家说一下当get或post的时候,tastypie的执行中比较重要的方法。
get的时候,会先执行ModelResource的obj_get方法再执行dehydrate方法。你可以继承dehydrate方法输出一些自己想额外添加的东西。
def dehydrate(self, bundle): bundle.data['is_test'] = True return bundle
post的时候,会执行主要执行的是obj_create方法。执行obj_create方法时,会先执行hydrate方法处理我们提交的数据。
bundle的data属性可以得到我们post提交的数据。bundle的obj属性可以得到我们要创建的对象。
在执行hydrate时,bundle.obj为None。hydrate主要是去掉一些杂质,得到创建对应的object需要的数据。
hydrate执行完成之后,再进行validation验证。tastypie的validation验证可以使用django的Form表单验证。
这样简化了很多格式等常规验证。但问题来了,通常API接口如果请求有问题时,我们需要返回对应的错误码。该错误码可以让API接口的使用者知道相应的错误,方便API接口使用者进行调试。
如果用Form表单验证,返回一个errors错误集合。该集合会将多个错误信息写在一起。而且该errors错误信息不能自定义,会直接暴露一些敏感字段名和容易被推测一些执行逻辑。
若不使用Form表单进行验证。那么在hydrate验证和validation验证有什么区别。
所以,本人觉得validation有些鸡肋。
我们继续顺着这个流程走下去。validation执行之后,会得到一个bundle.obj。该object是对应queryset绑定的相关model实例化对象。该object尚未被保存。
接着继续执行obj_create方法,真正创建object。
这里还会衍生另外一个问题:谁可以post,甚至更细致谁可以get、post、patch、delete等请求。该问题就是权限问题。
tastypie也提供了一些基本权限验证。对于复杂的权限需求,我个人更喜欢自定权限类。
#coding:utf-8 from tastypie.authorization import Authorization from tastypie.exceptions import Unauthorized class UserObjectsOnlyAuthorization(Authorization): def read_list(self, object_list, bundle): return object_list.filter(user=bundle.request.user) def read_detail(self, object_list, bundle): return bundle.obj.user == bundle.request.user def create_list(self, object_list, bundle): return object_list def create_detail(self, object_list, bundle): return bundle.obj.user == bundle.request.user def update_list(self, object_list, bundle): allowed = [] # Since they may not all be saved, iterate over them. for obj in object_list: if obj.user == bundle.request.user: allowed.append(obj) return allowed def update_detail(self, object_list, bundle): return bundle.obj.user == bundle.request.user def delete_list(self, object_list, bundle): raise Unauthorized("Sorry, no deletes.") def delete_detail(self, object_list, bundle): raise Unauthorized("Sorry, no deletes.")
在自定义权限中,bundle.obj对应的model要有user字段。该字段可以根据具体情况修改。
如果你某个ModelResource使用自定义权限类,但又有一些特殊的权限判断,例如判断身份级别。该判断可以重写authorized_delete_detail、authorized_update_detail等方法。这些方法是在权限验证之前执行。
可能你会问,权限验证是针对登录的用户或者没登录的访客。那么如何使用tastypie登录?
这点我也研究了很久。tastypie文档中提到api_key这个东西。可能我学识还不到家,没研究明白如何使用api_key。
所以,继续采用Django提供的登录方式。
#coding:utf-8 from tastypie.resources import ModelResource from tastypie.authorization import Authorization from tastypie.exceptions import Unauthorized from django.conf.urls import url from tastypie.utils import trailing_slash from django.contrib import auth class UserResource(ModelResource): class Meta: resource_name = 'user' queryset = User.objects.all() list_allowed_methods = ['get'] detail_allowed_methods = ['get'] authorization = Authorization() # 或者使用fields直接选择要显示的字段 fields = ['username', 'email'] def prepend_urls(self): urlpatterns = [ url(r'^(?P<resource_name>%s)/login%s' % (self._meta.resource_name, trailing_slash()), self.wrap_view('login'), name="api_login"), ] return urlpatterns def login(self, request, **kwargs): # 只允许POST提交 self.method_check(request, allowed=['post']) # 序列化提交的参数 data = self.deserialize(request, request.body, format=request.META.get('CONTENT_TYPE', 'application/json')) # 获得用户名和密码加密的密文 username = data.get('username', '') password = data.get('password', '') # 验证username是否是邮箱,实现可用邮箱登录 users = User.objects.filter(email=username) if users.count(): username = users[0].username # 登录 data = {} user = auth.authenticate(username=username, password=password) if user: auth.login(request, user) return self.create_response(request, {'stats':'OK'}) else: raise Unauthorized()
该处理方法是通过prepend_urls自定义一个api接口。通过该接口执行Django的登录方法。同样可以使用该方法创建登出的方法。
用户认证完整的功能还包括注册。注册实际上创建新的User,对应POST请求。这个大家可以试验一下。
初步使用大致体悟是这些。当然有关字段什么没讲,这些需要实践操作。更多体悟后面再说。有关tastypie欢迎多交流交流。
pengwk
😀
2018-06-13 15:00 回复