Package: lsshu-cms
Lsshuadmin@lsshu.cn安装pipinstalllsshu-cms使用1、在项目根目录新建文件main.pyfromfastapiimportFastAPIfromfastapi.middleware.corsimportCORSMiddlewarefromlsshu.oauth.mainimportrouterasrouter_oauthapp=FastAPI(title='Base API Docs',description='Base API接口文档',version='1.0.0')app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)app.include_router(router_oauth,prefix="/api")if__name__=='__main__':importuvicornuvicorn.run("main:app",host="0.0.0.0",port=8000,reload=True)2、在项目根目录新建python包app在包app下打开文件__init__.pyif__name__=='__main__':fromlsshu.oauth.modelimportModel,EngineModel.metadata.create_all(Engine)# 创建表结构APP_PERMISSIONS=[]fromconfigimportOAUTH_ADMIN_USERSfromlsshu.internal.helpersimportstore_permissions,init_user_and_passwordstore_permissions(APP_PERMISSIONS)# 初始化权限init_user_and_password(OAUTH_ADMIN_USERS)# 初始化授权用户3、在包app下新建python包demo在包demp下新建文件model.pyfromsqlalchemyimportColumn,Stringfromlsshu.internal.dbimportModelfromlsshu.internal.methodimportpluralname=plural(__name__.capitalize())table_name=name.replace('.','_')permission={"name":"Demo","scope":name,"action":[{"name":"de","scope":"de"}]}classModels(Model):""" 模型 """__tablename__=table_namename=Column(String(15),nullable=False,unique=True,comment="名称")4、在包demo下新建文件crud.pyfromlsshu.demo.modelimportModelsfromlsshu.internal.crudimportBaseCRUDclassCRUD(BaseCRUD):"""表操作"""params_model=Models5、在包demo下新建文件schema.pyfromdatetimeimportdatetimefromtypingimportOptional,ListfrompydanticimportBaseModelfromlsshu.internal.schemaimportSchemasPaginateclassSchemasResponse(BaseModel):"""模型 返回"""id:intname:Optional[str]=Nonecreated_at:Optional[datetime]=Noneupdated_at:Optional[datetime]=NoneclassConfig:orm_mode=TrueclassSchemasStoreUpdate(BaseModel):"""模型 提交"""name:Optional[str]=NoneclassSchemasPaginateItem(SchemasPaginate):items:List[SchemasResponse]classSchemasParams(BaseModel):pass6、在包demo下新建文件main.pyfromtypingimportListfromfastapiimportAPIRouter,Depends,HTTPException,status,Securityfromsqlalchemy.ormimportSessionfromlsshu.internal.dbimportdbsfromlsshu.internal.dependsimportmodel_screen_params,model_post_screen_params,auth_userfromlsshu.internal.schemaimportModelScreenParams,Schemasfromlsshu.oauth.user.schemaimportSchemasOAuthScopesfrom.crudimportCRUDfrom.modelimportnameasnamefrom.schemaimportSchemasResponse,SchemasParams,SchemasPaginateItem,SchemasStoreUpdaterouter=APIRouter(tags=["Demo"])scopes=[name,]@router.get('/{}'.format(name),name="get{}".format(name))asyncdefget_models(db:Session=Depends(dbs),params:ModelScreenParams=Depends(model_screen_params),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.list"%name])):""":param db::param params::param auth::return:"""db_model_list=CRUD.paginate(db=db,screen_params=params)returnSchemas(data=SchemasPaginateItem(**db_model_list))@router.post('/{}.post'.format(name),name="post{}".format(name))asyncdefpost_models(db:Session=Depends(dbs),params:ModelScreenParams=Depends(model_post_screen_params),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.list"%name])):""":param db::param params::param auth::return:"""db_model_list=CRUD.paginate(db=db,screen_params=params)returnSchemas(data=SchemasPaginateItem(**db_model_list))@router.get('/{}.params'.format(name),name="get{}".format(name))asyncdefparams_models(db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.list"%name])):""":param db::param auth::return:"""data={}returnSchemas(data=SchemasParams(**data))@router.get('/{}/{{pk}}'.format(name),name="get{}".format(name))asyncdefget_model(pk:int,db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.get"%name])):""":param pk::param db::param auth::return:"""db_model=CRUD.first(db=db,pk=pk)ifdb_modelisNone:raiseHTTPException(status_code=status.HTTP_404_NOT_FOUND,detail="{}not found".format(name.capitalize()))returnSchemas(data=SchemasResponse(**db_model))@router.post('/{}'.format(name),name="get{}".format(name))asyncdefstore_model(item:SchemasStoreUpdate,db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.store"%name])):""":param item::param db::param auth::return:"""db_model=CRUD.first(db=db,where=("name",item.name))ifdb_modelisnotNone:raiseHTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail="{}already registered".format(name.capitalize()))bool_model=CRUD.store(db=db,item=item)returnSchemas(data=SchemasResponse(**bool_model.to_dict()))@router.put("/{}/{{pk}}".format(name),name="update{}".format(name))asyncdefupdate_put_model(pk:int,item:SchemasStoreUpdate,db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.update"%name])):""":param pk::param item::param db::param auth::return:"""db_model=CRUD.first(db=db,pk=pk)ifdb_modelisNone:raiseHTTPException(status_code=status.HTTP_404_NOT_FOUND,detail="{}not found".format(name.capitalize()))bool_model=CRUD.update(db=db,pk=pk,item=item)returnSchemas(data=SchemasResponse(**bool_model.to_dict()))@router.patch("/{}/{{pk}}".format(name),name="update{}".format(name))asyncdefupdate_patch_model(pk:int,item:SchemasStoreUpdate,db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.update"%name])):""":param pk::param item::param db::param auth::return:"""db_model=CRUD.first(db=db,pk=pk)ifdb_modelisNone:raiseHTTPException(status_code=status.HTTP_404_NOT_FOUND,detail="{}not found".format(name.capitalize()))bool_model=CRUD.update(db=db,pk=pk,item=item,exclude_unset=True)returnSchemas(data=SchemasResponse(**bool_model.to_dict()))@router.delete("/{}/{{pk}}".format(name),name="delete{}".format(name))asyncdefdelete_model(pk:int,db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.delete"%name])):""":param pk::param db::param auth::return:"""bool_model=CRUD.delete(db=db,pk=pk)returnSchemas(data=bool_model)@router.delete("/{}".format(name),name="deletes{}".format(name))asyncdefdelete_role_models(pks:List[int],db:Session=Depends(dbs),auth:SchemasOAuthScopes=Security(auth_user,scopes=scopes+["%s.delete"%name])):""":param pks::param db::param auth::return:"""bool_model=CRUD.delete(db=db,pks=pks)returnSchemas(data=bool_model)7、在根目录下新建文件config.pyimportosROOT_PATH=os.path.dirname(__file__)# API 接口返回数据SCHEMAS_SUCCESS_CODE:int=0SCHEMAS_SUCCESS_STATUS:str='success'SCHEMAS_SUCCESS_MESSAGE:str='数据请求成功！'SCHEMAS_ERROR_CODE:int=1SCHEMAS_ERROR_STATUS:str='error'SCHEMAS_ERROR_MESSAGE:str='数据请求失败！'# 站点HOST_URL:str=""# 上传目录UPLOAD_NAME:str="static"UPLOAD_DIR:str="static"UPLOAD_URI:str="/static"# OAuth 授权相关OAUTH_DEFAULT_TAGS:list=['OAuth']OAUTH_LOGIN_SCOPES:str="login"OAUTH_TOKEN_URI:str="/token"OAUTH_TOKEN_URL:str="/api%s"%OAUTH_TOKEN_URIOAUTH_SCOPES_URI:str="/scopes"OAUTH_TOKEN_SCOPES:dict={OAUTH_LOGIN_SCOPES:OAUTH_LOGIN_SCOPES.capitalize()}OAUTH_SECRET_KEY:str="4a876f7766d1a0e9d97231089be927e38d6dea09233ad212f056b7f1a75cd41d"OAUTH_ALGORITHM:str="HS256"OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES:int=300OAUTH_OAUTH_ROUTER:dict={}# 超级管理员 账号:密码OAUTH_ADMIN_USERS:dict={"admin":"admin"}# 数据库相关DB_SQLALCHEMY_DATABASE_URL:str="sqlite:///{}".format(os.path.join(ROOT_PATH,'db.sqlite3'))# DB_SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:root@192.168.1.3:3306/ic" # ic 数据库# echo=True表示引擎将用repr()函数记录所有语句及其参数列表到日志# 由于SQLAlchemy是多线程，指定check_same_thread=False来让建立的对象任意线程都可使用。这个参数只在用SQLite数据库时设置DB_ENGINE_KWARGS:dict={# "echo": True,# "encoding": 'utf-8',# "pool_pre_ping": True,# "pool_size": 100,# "pool_recycle": 3600,# "max_overflow": 100,"connect_args":{'check_same_thread':False,# "charset": "utf8mb4"}}# 在SQLAlchemy中，CRUD都是通过会话(session)进行的，所以我们必须要先创建会话，每一个SessionLocal实例就是一个数据库session# flush()是指发送数据库语句到数据库，但数据库不一定执行写入磁盘；commit()是指提交事务，将变更保存到数据库文件DB_SESSION_MAKER_KWARGS:dict={"autoflush":False,"autocommit":False,"expire_on_commit":True}8、在根目录下新建文件.gitignore.idea
Desktop.ini
db.sqlite3
.DS_Store
*__pycache__*docker 部署1、在根目录下新建文件DockerfileFROMpython:3.8WORKDIR/appEXPOSE80RUNmkdir-p/app&&pipinstalllsshu-cmsCMD["uvicorn","main:app","--host","0.0.0.0","--port","80","--reload"]2、创建镜像并运行dockerbuild-tproject_name.&&dockerrun-d--nameproject_name-v/projects/project_path:/app-p49000:80project_name@project_name 项目名称; /projects/project_path 项目所在的目录; 49000 宿主机端口; 80 容器端口;3、删除容器和镜像dockerstopproject_name&&dockerrmproject_name&&dockerrmiproject_namenginx 部署http{upstreamproject_server{server0.0.0.0:49000weight=1;}server{listen80;server_nameproject.com;indexindex.htmlindex.htm;root/projects/project_path/dist;try_files$uri$uri//index.html;location/static/{alias/projects/project_path/static/;#静态资源路径}location~/api|/docs|/openapi.json{proxy_passhttp://project_server;# 配置websocketproxy_http_version1.1;proxy_set_headerUpgrade$http_upgrade;proxy_set_headerConnection"upgrade";# 其它代理proxy_set_headerHttp_Referer$http_referer;proxy_set_headerHost$host:$server_port;proxy_set_headerX-real-ip$remote_addr;}location~^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|app|main\.py|config\.py){return404;}}}@root /projects/project_path/dist 其中dist可为前端打包的目录；其它根据自身增减