Overview Sanic is a Python 3.7+ web server and web framework that’s written to go fast. It allows the usage of the async/await syntax added in Python 3.5, which makes your code non-blocking and speedy.
Example 下面是一个简单的例子,使用到如下库:
sanic (sanic is a flask-like python3.5 + web server) peewee (simple and small ORM) PyMySQL (mysql database driver) marshmallow (serialize and deserialize models) AoikLiveReload (automatic reload app in development)
目录结构
启动服务 (sanic) [blazehu@MacBook ~]$ python3 app.py 2018-12-21 10:53:50 - (sanic)[INFO]: Goin' Fast @ http://0.0.0.0:8000 2018-12-21 10:53:50 - (sanic)[INFO]: Starting worker [44832]
访问测试 create a new employee
list employees
logs
(sanic) [blazehu@MacBook ~]$ python3 app.py 2018-12-21 10:53:50 - (sanic)[INFO]: Goin' Fast @ http://0.0.0.0:8000 2018-12-21 10:53:50 - (sanic)[INFO]: Starting worker [44832] 2018-12-21 10:59:54 - (network)[INFO ][127.0.0.1:55817 ]: GET http://127.0.0.1:8000/employee/ 200 267 2018-12-21 11:00:03 - (network)[INFO ][127.0.0.1:55865 ]: GET http://127.0.0.1:8000/employee/ 200 267 2018-12-21 11:01:05 - (network)[INFO ][127.0.0.1:56135 ]: GET http://127.0.0.1:8000/employee/ 200 38 2018-12-21 11:01:44 - (network)[INFO ][127.0.0.1:56325 ]: POST http://127.0.0.1:8000/employee/ 200 28 2018-12-21 11:02:38 - (network)[INFO ][127.0.0.1:56562 ]: GET http://127.0.0.1:8000/employee/ 200 95
具体实现 models.py from peewee import *from playhouse.pool import MySQLDatabasefrom playhouse.shortcuts import RetryOperationalErrorimport configclass RetryMysqlDatabase (RetryOperationalError, MySQLDatabase) : def __init__ (self, database, **kwargs) : super(MySQLDatabase, self).__init__(database, **kwargs) def sequence_exists (self, seq) : pass db = RetryMysqlDatabase( database=config.DB_NAME, host=config.DB_HOST, user=config.DB_USER, passwd=config.DB_PASSWORD, port=config.DB_PORT, ) class BaseModel (Model) : """A base model that will use our MySQL database""" is_deleted = BooleanField(u'是否删除' , default=False ) class Meta : database = db class Employee (BaseModel) : number = CharField(verbose_name=u'编号' , unique=True ) name = CharField(verbose_name=u'姓名' , null=True ) email = CharField(verbose_name=u'邮箱' , null=True )
serialize.py from marshmallow import Schema, fields, post_loadimport modelsclass EmployeeSchema (Schema) : number = fields.String() name = fields.String() email = fields.Email() @post_load def make_employee (self, data) : return models.Employee(**data)
views.py from sanic.views import HTTPMethodViewfrom sanic import Blueprint, responsefrom models import Employeeimport serializeemployee_bp = Blueprint("employee_bp" ) class EmployeeView (HTTPMethodView) : async def get (self, request) : employees = Employee.select().where(Employee.is_deleted == 0 ) schema = serialize.EmployeeSchema() data = schema.dump(employees, many=True ).data return response.json({"code" : 200 , "msg" : "success" , "data" : data}) async def post (self, request) : data = request["POST" ] employee_schema = serialize.EmployeeSchema() _, error = employee_schema.load(data) if error: msg = "" for error_item in error: error_detail = error.get(error_item) if isinstance(error_detail, list): error_detail = ',' .join(error_detail) else : error_detail = str(error_detail) msg += "{0}: {1}" .format(error_item, error_detail) return response.json({"code" : 500 , "msg" : msg}) else : number = data.get("number" ) try : Employee.get(Employee.number == number) return response.json({"code" : 500 , "msg" : "the number is uniq" }) except Employee.DoesNotExist: employee = Employee() for key in data: value = data.get(key) if hasattr(employee, key): setattr(employee, key, value) employee.save() return response.json({"code" : 201 , "msg" : "success" }) employee_bp.add_route(EmployeeView.as_view(), "/" )
app.py from sanic import Sanicfrom sanic_cors import CORSfrom aoiklivereload import LiveReloaderfrom views import employee_bpfrom models import db, Employeeimport configapp = Sanic(__name__) app.blueprint(employee_bp, url_prefix='/employee' ) CORS(app, automatic_options=True ) @app.middleware('request') async def transform_data_request (request) : try : request['POST' ] = request.json if request.json else {} request['GET' ] = request.args if request.args else {} except Exception as e: print(repr(e)) @app.middleware('response') async def close_db (request, response) : if not db.is_closed(): db.close() app.config.from_object(config) db.create_tables([Employee, ], safe=True ) if __name__ == '__main__' : reloader = LiveReloader() reloader.start_watcher_thread() app.run(host='0.0.0.0' , port=8000 , debug=True )
config.py KEEP_ALIVE = False LOGO = None DB_HOST = '127.0.0.1' DB_PORT = 3306 DB_NAME = 'sanic' DB_USER = 'root' DB_PASSWORD = '123456'
requirements.txt # python 3.7 .2 PyMySQL==0.7 .11 AoikLiveReload==0.1 .0 peewee==2.8 .5 marshmallow==2.13 .6 sanic-crud==0.2 .4 Sanic-Cors==0.6 .0 .0 sanic==0.6 .0
start.sh python3 app.py gunicorn app:app --bind 0.0.0.0:8000 --worker-class sanic.worker.GunicornWorker