- 数据库:PostgreSQL
- 框架:Flask
- 语言:Python 3.6
前提
- 之前我有每天定时爬取bing壁纸,写入postgresql数据库的,如下:
- ER图
需要的Python环境
- flask-sqlalchemy
- flask-migrate
- flask-script
- flask-restful
- flask
- psycopg2
创建配置文件Config.py
里面设置数据库的引擎以及其它的一些需要配置的程序参数
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 18/6/25 下午5:15 # @Author : olei # @File : Config.py # @Software: PyCharm # @license : Copyright(C), iicats.com # @Contact : i@olei.me DB_USER = "postgres" DB_PASSWORD = "postgres" HOST = "127.0.0.1" DB_NAME = "bing" DEBUG = True SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_DATABASE_URI = 'postgresql://' + DB_USER + ':' + DB_PASSWORD + "@" + HOST + '/' + DB_NAME
这里设置的是postgresql的配置项
数据模型Model.py
根据数据库,来设置数据模型
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 18/6/25 下午5:22 # @Author : olei # @File : Model.py # @Software: PyCharm # @license : Copyright(C), iicats.com # @Contact : i@olei.me from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Bing(db.Model): __tablename__ = "psql_bing" id = db.Column(db.Integer,unique=True,primary_key=True) dates = db.Column(db.Date,nullable=False) bing_url = db.Column(db.String(10000),nullable=False) qiniu_url = db.Column(db.String(10000),nullable=False) image_name = db.Column(db.String(10000),nullable=False)
忽略我给的String的大小...,这个与flask中设计表结构的写法是一致的,用到flask的flask-sqlalchemy
数据库迁移文件migrate.py
使用Flask-Migrate和Flask-Script来实现数据迁移
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 18/6/25 下午5:25 # @Author : olei # @File : migrate.py # @Software: PyCharm # @license : Copyright(C), iicats.com # @Contact : i@olei.me from flask import Flask from flask_migrate import Migrate,MigrateCommand from flask_script import Manager from Model import db app = Flask(__name__) app.config.from_object('Config') migrate = Migrate(app,db) manager = Manager(app) manager.add_command('db',MigrateCommand) if __name__ == "__main__": manager.run()
这里的 app.config.from_object 是读取配置文件,里面写上配置文件的没有拓展名的文件名,就是上面的配置文件Config.py 的名字
- 定义好数据迁移配置后,执行下面命令完成数据迁移:
$ python migrate.py db init $ python migrate.py db migrate $ python migrate.py db upgrade
结束之后会生成一个文件夹,里面也会生成一些文件,如下:
migrations ├── README ├── alembic.ini ├── env.py ├── script.py.mako └── versions └── 79d73a8da1cf_.py
Flask-RESTful接口实现app.py
- 先给出代码
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 18/6/26 上午11:21 # @Author : olei # @File : app.py # @Software: PyCharm # @license : Copyright(C), iicats.com # @Contact : i@olei.me from flask import Flask, jsonify from Model import db, Bing from flask_restful import Resource, Api, reqparse, fields, marshal_with, abort, marshal app = Flask(__name__) app.config.from_object("Config") db.init_app(app) errors = { 'BingAlreadyExistsError': { 'message': "It is already exists.", 'status': 409, }, 'ResourceDoesNotExist': { 'message': "A resource with that ID no longer exists.", 'status': 410, 'extra': "Any extra information you want.", }, } api = Api(app, catch_all_404s=True, errors=errors) parser = reqparse.RequestParser() parser.add_argument('dates', required=True) parser.add_argument('bing_url', required=True) parser.add_argument('qiniu_url', required=True) # parser.add_argument('user_nickname') parser.add_argument('image_name', required=True) resource_full_fields = { 'id': fields.Integer, 'dates': fields.String, 'bing_url': fields.String, 'qiniu_url': fields.String, 'image_name': fields.String } class Common: def returnTrueJson(self, data, msg="请求成功"): return jsonify({ "status": 1, "data": data, "msg": msg }) def returnFalseJson(self, data=None, msg="请求失败"): return jsonify({ "status": 0, "data": data, "msg": msg }) class Hello(Resource): def get(self): return 'Hello Flask!' class Bing_all(Resource): def get(self): # dates = Bing.query.filter_by() return Common.returnTrueJson(Common, marshal(Bing.query.all(), resource_full_fields)) class Bing_url(Resource): def get(self, dates): dates = Bing.query.filter_by(dates=dates).first() if (dates is None): abort(410, msg="找不到数据!", data=None, status=0) else: return Common.returnTrueJson(Common, marshal(dates, resource_full_fields)) api.add_resource(Hello, '/', '/hello') api.add_resource(Bing_all, '/bing') api.add_resource(Bing_url, '/bing/<string:dates>') if __name__ == "__main__": app.run(debug=app.config['DEBUG'])
分析
- 错误处理代码
errors = { 'BingAlreadyExistsError': { 'message': "It is already exists.", 'status': 409, }, 'ResourceDoesNotExist': { 'message': "A resource with that ID no longer exists.", 'status': 410, 'extra': "Any extra information you want.", }, } api = Api(app, catch_all_404s=True, errors=errors)
调用是通过abort来调用的
if (dates is None): abort(410, msg="找不到数据!", data=None, status=0)
- 定义一个Common,来统一响应数据格式
- 处理请求
Flask-RESTful的reqparse用于获取并转化客户端输入参数
parser = reqparse.RequestParser() parser.add_argument('dates', required=True) parser.add_argument('bing_url', required=True) parser.add_argument('qiniu_url', required=True) # parser.add_argument('user_nickname') parser.add_argument('image_name', required=True)
上面代码定义了一个请求数据分析转化器(parser),然后指定参数的名称。
在获取参数数据时使用parse_args来转化所有的参数,并返回一个输入数据字典。
代码里面没有用到,这个是post,delete等请求会用到,就是增删改用
- 处理响应
Flask-RESTful的fields用于规范响应字段,定制响应字段键名和键值数据类型,还可以对输出响应做更多复杂的处理。输出响应时,可以使用装饰器或函数式两种方式作处理:
装饰器方式:
@marshal_with(resource_full_fields, envelope=’data’)
函数方式:
marshal(User.query.all()
代码中用了函数方式来处理
运行
$ python app.py
后记
忽略app.py中我对dates的处理...
- 优化版的源码放到github上了:源码
本文作者为olei,转载请注明。