Sanic简易框架搭建
模型层搭建
from sqlalchemy import INTEGER, Column, ForeignKey, String
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import create_engine
Base = declarative_base()
class BaseModel(Base):
__abstract__ = True
id = Column(INTEGER(), primary_key=True, autoincrement=True)
class Person(BaseModel):
__tablename__ = "person"
name = Column(String(50))
cars = relationship("Car")
def to_dict(self):
return {"name": self.name, "car": [{"brand": car.brand} for car in self.cars]}
class Car(BaseModel):
__tablename__ = "car"
brand = Column(String(50))
user_id = Column(ForeignKey("person.id"))
user = relationship("Person", back_populates="cars")
# 迁移表数据,迁移表数据,迁移完成之后即可注释掉
# bind = create_engine("mysql+pymysql://root:000000@localhost/car", echo=True) # 连接mysql数据库,相当于django中migrate命令
# Base.metadata.create_all(bind)
视图层与路由层
from sanic import Sanic
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from sanic.response import json
from models import Car, Person
app = Sanic(__name__)
from middleware import inject_session
@app.post("/user") # 注册路由
async def create_user(request): # 视图函数
session = request.ctx.session # 先执行中间件内容,具体代码在middleware.py中。
print(session)
async with session.begin():
car = Car(brand="Tesla")
person = Person(name="foo", cars=[car])
session.add_all([person])
return json(person.to_dict())
# app.add_route(create_user, '/user', methods=['POST']) # 注册路由的第二种方式
@app.get("/user/<pk:int>") # 注册路由
async def get_user(request, pk): # 视图函数
print("查询,", pk)
# print('-------',request.ctx.text)
session = request.ctx.session
async with session.begin():
stmt = select(Person).where(Person.id == pk).options(selectinload(Person.cars))
result = await session.execute(stmt)
person = result.scalar()
if not person:
return json({})
return json(person.to_dict())
# app.add_route(get_user, '/user/<pk:int>', methods=['GET']) # 注册路由的第二种方式
if __name__ == "__main__": # 启动run
app.register_middleware(inject_session, "request")
app.run(port=8000)
这边的session变量中的数据值是可以在中间件中修改的,传入数据库引擎即携带异步数据库中的真实数据,可自行改变传入值或对象。
中间件层
from contextvars import ContextVar
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.asyncio import create_async_engine
bind = create_async_engine("mysql+aiomysql://root:000000@localhost/car", echo=True) # 异步实现数据传输
_sessionmaker = sessionmaker(bind, AsyncSession, expire_on_commit=False)
_base_model_session_ctx = ContextVar("session")
async def inject_session(request):
request.ctx.session = _sessionmaker()
# request.ctx.text = [{}]
request.ctx.session_ctx_token = _base_model_session_ctx.set(request.ctx.session)
async def close_session(request, response):
if hasattr(request.ctx, "session_ctx_token"):
_base_model_session_ctx.reset(request.ctx.session_ctx_token)
await request.ctx.session.close()