update python_restful_api.py

master
xianhu 2017-01-11 12:19:23 +08:00
parent a9dff55397
commit 1cdf0f4dfe
2 changed files with 149 additions and 37 deletions

View File

@ -38,6 +38,8 @@
### python_restful_api.py: 利用Python和Flask快速开发RESTful API
### python_restful_api.py: RESTful API进阶: 连接数据库、添加参数、Token认证、返回代码说明等
### python_context.py: With语句和上下文管理器ContextManager
===================================================================================================

View File

@ -4,72 +4,182 @@
python_restful_api.py by xianhu
"""
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
import sqlalchemy
import sqlalchemy.orm
import sqlalchemy.ext.declarative
from flask import Flask, g
from flask_restful import reqparse, Api, Resource
from flask_httpauth import HTTPTokenAuth
# Flask相关变量声明
app = Flask(__name__)
api = Api(app)
ITEMS = {
'item1': {'name': 'Allen', 'age': 19},
'item2': {'name': 'Lily', 'age': 18},
'item3': {'name': 'James', 'age': 20},
# 认证相关
auth = HTTPTokenAuth(scheme="token")
TOKENS = {
"fejiasdfhu",
"fejiuufjeh"
}
def abort_if_item_doesnt_exist(item_id):
if item_id not in ITEMS:
abort(404, message="Item {} doesn't exist".format(item_id))
@auth.verify_token
def verify_token(token):
if token in TOKENS:
g.current_user = token
return True
return False
def get_new_item_id():
for key in ITEMS:
item_id = 'item' + str(int(key.strip('item')) + 1)
if item_id not in ITEMS:
return item_id
# 数据库相关变量声明
engine = sqlalchemy.create_engine("mysql+pymysql://username:password@ip/db_name", encoding="utf8", echo=False)
BaseModel = sqlalchemy.ext.declarative.declarative_base()
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, required=True, help='need name data')
parser.add_argument('age', type=int, required=True, help='need age data')
# 构建数据模型User
class User(BaseModel):
__tablename__ = "Users"
__table_args__ = {
"mysql_engine": "InnoDB",
"mysql_charset": "utf8",
}
# 表结构,具体更多的数据类型自行百度
id = sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True, autoincrement=True)
name = sqlalchemy.Column("name", sqlalchemy.String(50), nullable=False)
age = sqlalchemy.Column("age", sqlalchemy.Integer, nullable=False)
# 构建数据模型的json格式
def get_json(user):
return {"id": user.id, "name": user.name, "age": user.age}
# 利用Session对象连接数据库
DBSessinon = sqlalchemy.orm.sessionmaker(bind=engine)
session = DBSessinon()
BaseModel.metadata.drop_all(engine)
BaseModel.metadata.create_all(engine)
# RESTfulAPI的参数解析 -- put / post参数解析
parser_put = reqparse.RequestParser()
parser_put.add_argument("name", type=str, required=True, help="need name data")
parser_put.add_argument("age", type=int, required=True, help="need age data")
# RESTfulAPI的参数解析 -- get参数解析
parser_get = reqparse.RequestParser()
parser_get.add_argument("limit", type=int, required=False)
parser_get.add_argument("offset", type=int, required=False)
parser_get.add_argument("sortby", type=str, required=False)
# 操作put / get / delete单一资源
class Todo(Resource):
# 添加认证
decorators = [auth.login_required]
def put(self, item_id):
args = parser.parse_args()
item = {'name': args['name'], 'age': args['age']}
ITEMS[item_id] = item
return item, 201
def put(self, user_id):
"""
更新用户数据: curl http://127.0.0.1:5000/users/1 -X PUT -d "name=Allen&age=20" -H "Authorization: token fejiasdfhu"
"""
args = parser_put.parse_args()
user_ids_set = set([user.id for user in session.query(User.id)])
print(user_ids_set)
def get(self, item_id):
abort_if_item_doesnt_exist(item_id)
return ITEMS[item_id], 200
# 用户不存在返回404
if user_id not in user_ids_set:
return None, 404
def delete(self, item_id):
abort_if_item_doesnt_exist(item_id)
del ITEMS[item_id]
return '', 204
# 更新用户数据
user = session.query(User).filter(User.id == user_id)[0]
user.name = args["name"]
user.age = args["age"]
session.merge(user)
session.commit()
# 更新成功返回201
return get_json(user), 201
def get(self, user_id):
"""
获取用户数据: curl http://127.0.0.1:5000/users/1 -X GET -H "Authorization: token fejiasdfhu"
"""
users = session.query(User).filter(User.id == user_id)
# 用户不存在返回404
if users.count() == 0:
return None, 404
# 返回用户数据
return get_json(users[0]), 200
def delete(self, user_id):
"""
删除用户数据: curl http://127.0.0.1:5000/users/1 -X DELETE -H "Authorization: token fejiasdfhu"
"""
session.query(User).filter(User.id == user_id).delete()
return None, 204
# 操作post / get资源列表
class TodoList(Resource):
# 添加认证
decorators = [auth.login_required]
def get(self):
return ITEMS, 200
"""
获取全部用户数据: curl http://127.0.0.1:5000/users -X GET -d "limit=2&offset=0&sortby=name" -H "Authorization: token fejiasdfhu"
"""
args = parser_get.parse_args()
users = session.query(User)
# 根据条件查询
if "sortby" in args:
users = users.order_by(User.name if args["sortby"] == "name" else User.age)
if "offset" in args:
users = users.offset(args["offset"])
if "limit" in args:
users = users.limit(args["limit"])
# 返回结果
return [get_json(user) for user in users], 200
def post(self):
args = parser.parse_args()
item_id = get_new_item_id()
ITEMS[item_id] = {'name': args['name'], 'age': args['age']}
return ITEMS[item_id], 201
"""
添加一个新用户: curl http://127.0.0.1:5000/users -X POST -d "name=Brown&age=20" -H "Authorization: token fejiasdfhu"
"""
args = parser_put.parse_args()
# 构建新用户
user = User(name=args["name"], age=args["age"])
session.add(user)
session.commit()
# 资源添加成功返回201
return get_json(user), 201
# 设置路由
api.add_resource(TodoList, '/items')
api.add_resource(Todo, '/items/<item_id>')
api.add_resource(TodoList, "/users")
api.add_resource(Todo, "/users/<int:user_id>")
if __name__ == '__main__':
if __name__ == "__main__":
app.run(debug=True)
""" 常见返回代码
200 OK - [GET]服务器成功返回用户请求的数据
201 CREATED - [POST/PUT/PATCH]用户新建或修改数据成功
202 Accepted - [*]表示一个请求已经进入后台排队异步任务
204 NO CONTENT - [DELETE]用户删除数据成功
400 INVALID REQUEST - [POST/PUT/PATCH]用户发出的请求有错误服务器没有进行新建或修改数据的操作
401 Unauthorized - [*]表示用户没有权限令牌用户名密码错误
403 Forbidden - [*] 表示用户得到授权与401错误相对但是访问是被禁止的
404 NOT FOUND - [*]用户发出的请求针对的是不存在的记录服务器没有进行操作
406 Not Acceptable - [GET]用户请求的格式不可得
410 Gone -[GET]用户请求的资源被永久删除且不会再得到的
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时发生一个验证错误
500 INTERNAL SERVER ERROR - [*]服务器发生错误用户将无法判断发出的请求是否成功
"""