pythonweb开发项目经验_Python Web开发我的学习经验--3、Web API具体开发

从上期开始我们完成了项目的最简单的演示,配置两个不同路径,就完成Http四个动词的操作,Get(所有,以及通过ID获取)、Post(新增)、Delete(通过ID删除)、Put(Patch的操作,Put会将未填写的字段置空)。

由于resource的url是两个不同的路径注册,所以四个动词五大操作是分别放置在两个类中的,如Todo以及TodoList中。其中TodoList包含Get(GetAll,可以加分页),Post(新增),Todo则在URL中有Id信息,可以具体到单个实体,所以有Get(获取单个实体),Delete(删除)、Put(Patch更新)。

api.add_resource(TodoList, '/todos')

api.add_resource(Todo, '/todos/')

下面开始完整的从实体类到restful四个动词五大操作的过程。

1、定义实体类

根据具体需求和业务,定义实体类,如Developer(开发人员)。需要保存开发人员的

编号(code),姓名(name),描述(desc),类型(type如Android,后台等)。

编写Developer类,按1、准备工作中说明要实现三个基类:db.Model, JsonModel, DbOperate,其中增加ID主键,自增。

class Developer(db.Model, JsonModel, DbOperate):

__tablename__ = 'developers'

tojson = "id,code,name,desc,type"

id = db.Column(db.Integer, primary_key=True)

code = db.Column(db.String(256), nullable=False)

name = db.Column(db.String(256), nullable=False)

desc = db.Column(db.TEXT, nullable=True)

type = db.Column(db.String(256), nullable=True)

date_created = db.Column(db.DateTime, default=db.func.now())

date_modified = db.Column(

db.DateTime, default=db.func.now(),

onupdate=db.func.now())

其中date_created:为创建进时间,

date_modified:为修改时间,密码为操作当前时间。

将Developer放在App\models.py中,现在开始编写入口路径路由,以及定义Resource。

在app\api\__init__.py中导入DevelopersResouce以及DeveloperResouce,从而配置好路由。

api.add_resource(DevelopersResouce, "/api/v1.0/developers")

api.add_resource(DeveloperResouce, "/api/v1.0/developers/")

现在主要面对的是DevelopersResouce和DeveloperResouce,代码如下:

from ..bizviews import IDResource,IDsResource

from ..models import Developer

class DevelopersResouce(IDsResource):

def getModel(self):

return Developer

class DeveloperResouce(IDResource):

def getModel(self):

return Developer

现在的问题是基类IDResource和IDsResource到底做了些什么?

为什么能达到不用编写代码就可以实现四个Http动词五个动作,先看代码:

from flask_restful import Resource

from .restfuls import doGet, dopostordeleteorput, doerror

from flask import request

class IDResource(Resource):

def __init__(self):

self.cls = self.getModel()

def getModel(self):

pass

def get(self, id):

def handler(user_id):

module = self.cls.query.get(id)

return module

return doGet(handler)

def put(self, id):

def handler(user_id):

module = self.cls.fromDict(request.json)

oldmodule = self.cls.query.get(id)

if oldmodule is None:

oldmodule = self.cls(id=id)

oldmodule.putUpdate(module)

oldmodule.save()

return dopostordeleteorput(handler)

def delete(self, id):

def handler(user_id):

oldmodule = self.cls.query.get(id)

oldmodule.delete()

return dopostordeleteorput(handler)

class IDsResource(Resource):

def __init__(self):

self.cls = self.getModel()

def getModel(self):

pass

def get(self):

def handler(user_id):

users = self.cls.query.all()

return users

return doGet(handler)

def post(self):

def handler(user_id):

module = self.cls.fromDict(request.json)

if self.checkpost(user_id, module):

return doerror(667)

self.prepost(module)

module.save()

self.afterPost(module)

return dopostordeleteorput(handler)

def checkpost(self, user_id, module):

return self.cls.query.filter_by(name=module.name) \

.first() is not None

def prepost(self, module):

pass

def afterPost(self, module):

pass

相同代码出现时就应该考虑提取函数,拥抱变化,将变化的和不变的分开,通过多态或泛型等能想到的办法去保证只有一份代码。

先看IDsResource,实现了get和post方法,其中get方法相对简单,只需要cls类。由于Python无法像Java、C#这样写泛型,所以人为定义一个方法 def getModel(self),实现IDsResouce的子类override该方法,从而达到子类使用具体的类。也将变化的部分和不变的部分分开。尤其是Post方法,还做了很多预留,checkpost是在保存前进行检测,比如code不能重复,就需要子类重写该方法,而prepost是保存前操作,afterPost则是保存后操作。

IDResouce相对来说比较简单,只有Put方法有一些复杂的操作,其实在delete时也应该有预留方法,比如关联的表数据也要删除,这里只要是Demo,所以没有处理。比如IDsResouce的get方法也没有做分页处理。

测试:第一次访问

此时没有任何数据,测试Post新增,编写Json:

{

"code":"hwh",

"name":"黄卫华",

"type":"android"

}

测试:

测试查看结果:

测试单个用例:

这里一直有一个token在这里,就涉及到登录信息,以及Token怎样验证的情况。

仔细查看IDsResouce和IDResouce就会发现里有几个不太认识的方法:

doGet:用于处理Get方法所做操作模板

dopostordeleteorput:用于处理其他三个方法所做操作模板

具体实现代码:

def doGet(handler):

token = request.headers.get('token')

if token:

user_id, status = User.decode_token(token)

if status == 200:

return dosuccess(handler(user_id))

else:

return doerror(status)

return doerror(666)

def dosuccess(users):

response = Response()

response.setData(users)

return response.toDict() , 200

def doerror(status):

response = Response(status=status)

return response.toDict() , status

def doexception(msg):

response = Response()

response.setException(msg)

return response.toDict(), 999

def dopostordeleteorput(handler):

token = request.headers.get('token')

if token:

user_id, status = User.decode_token(token)

if status == 200:

try:

handler(user_id)

return dosuccess(None)

except DataExistsException:

return doerror(667)

except Exception as e:

return doexception(str(e))

else:

return doerror(status)

else:

doerror(666)

token = request.headers.get('token') 获取头件中的token,然后进行验证,

user_id, status = User.decode_token(token)

详见代码。这种办法代码也只在一个地方编写,还有更优雅的办法通过装饰器,以后会进一步介绍。

其他的几个实体类的资源文件也是类似的如下:

from ..bizviews import IDResource, IDsResource

from ..models import User

class UsersResouce(IDsResource):

def getModel(self):

return User

class UserResouce(IDResource):

def getModel(self):

return User

from ..bizviews import IDResource,IDsResource

from ..models import ModuleInfo

class ModuleInfosResouce(IDsResource):

def getModel(self):

return ModuleInfo

class ModuleInfoResouce(IDResource):

def getModel(self):

return ModuleInfo

到现在为至,基本功能完成。而标准的Restful的编写也非常简单,只要配置一下GetModel就可以,以后会进一步讲解授权验证以及权限。请继续关注。

请关注我的公众号:9i编程9i编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值