lsshu-cms


Namelsshu-cms JSON
Version 2.1.0 PyPI version JSON
download
home_pagehttps://github.com/lsshu/fastapi-cms
SummaryFastAPI 开发的CMS
upload_time2023-04-06 10:00:59
maintainer
docs_urlNone
authorLsshu
requires_python>=3.9
licenseGPLv3
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Lsshu 
_admin@lsshu.cn_

## 安装
```shell
pip install lsshu-cms
```

## 使用
_1、在项目根目录新建文件 **`main.py`**_ 
```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from lsshu.oauth.main import router as router_oauth

app = 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__':
    import uvicorn

    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
```

_2、在项目根目录新建python包 **`app`** 在包app下打开文件 **`__init__.py`**_ 
```python
if __name__ == '__main__':
    from lsshu.oauth.model import Model, Engine

    Model.metadata.create_all(Engine)  # 创建表结构

    APP_PERMISSIONS = []

    from config import OAUTH_ADMIN_USERS
    from lsshu.internal.helpers import store_permissions, init_user_and_password

    store_permissions(APP_PERMISSIONS)  # 初始化权限
    init_user_and_password(OAUTH_ADMIN_USERS)  # 初始化授权用户
```

_3、在包app下新建python包 **`demo`** 在包demp下新建文件 **`model.py`**_ 
```python
from sqlalchemy import Column, String

from lsshu.internal.db import Model
from lsshu.internal.method import plural

name = plural(__name__.capitalize())
table_name = name.replace('.', '_')
permission = {"name": "Demo", "scope": name, "action": [{"name": "de", "scope": "de"}]}


class Models(Model):
    """ 模型 """
    __tablename__ = table_name
    name = Column(String(15), nullable=False, unique=True, comment="名称")
```

_4、在包demo下新建文件 **`crud.py`**_ 
```python
from lsshu.demo.model import Models
from lsshu.internal.crud import BaseCRUD


class CRUD(BaseCRUD):
    """表操作"""
    params_model = Models
```

_5、在包demo下新建文件 **`schema.py`**_ 
```python
from datetime import datetime
from typing import Optional, List

from pydantic import BaseModel

from lsshu.internal.schema import SchemasPaginate


class SchemasResponse(BaseModel):
    """模型 返回"""
    id: int
    name: Optional[str] = None
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

    class Config:
        orm_mode = True


class SchemasStoreUpdate(BaseModel):
    """模型 提交"""
    name: Optional[str] = None


class SchemasPaginateItem(SchemasPaginate):
    items: List[SchemasResponse]


class SchemasParams(BaseModel):
    pass
```
_6、在包demo下新建文件 **`main.py`**_ 
```python
from typing import List

from fastapi import APIRouter, Depends, HTTPException, status, Security
from sqlalchemy.orm import Session

from lsshu.internal.db import dbs
from lsshu.internal.depends import model_screen_params, model_post_screen_params, auth_user
from lsshu.internal.schema import ModelScreenParams, Schemas
from lsshu.oauth.user.schema import SchemasOAuthScopes

from .crud import CRUD
from .model import name as name
from .schema import SchemasResponse, SchemasParams, SchemasPaginateItem, SchemasStoreUpdate

router = APIRouter(tags=["Demo"])
scopes = [name, ]


@router.get('/{}'.format(name), name="get {}".format(name))
async def get_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)
    return Schemas(data=SchemasPaginateItem(**db_model_list))


@router.post('/{}.post'.format(name), name="post {}".format(name))
async def post_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)
    return Schemas(data=SchemasPaginateItem(**db_model_list))


@router.get('/{}.params'.format(name), name="get {}".format(name))
async def params_models(db: Session = Depends(dbs), auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + ["%s.list" % name])):
    """
    :param db:
    :param auth:
    :return:
    """

    data = {}
    return Schemas(data=SchemasParams(**data))


@router.get('/{}/{{pk}}'.format(name), name="get {}".format(name))
async def get_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)
    if db_model is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="{} not found".format(name.capitalize()))
    return Schemas(data=SchemasResponse(**db_model))


@router.post('/{}'.format(name), name="get {}".format(name))
async def store_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))
    if db_model is not None:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail="{} already registered".format(name.capitalize()))
    bool_model = CRUD.store(db=db, item=item)
    return Schemas(data=SchemasResponse(**bool_model.to_dict()))


@router.put("/{}/{{pk}}".format(name), name="update {}".format(name))
async def update_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)
    if db_model is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="{} not found".format(name.capitalize()))
    bool_model = CRUD.update(db=db, pk=pk, item=item)
    return Schemas(data=SchemasResponse(**bool_model.to_dict()))


@router.patch("/{}/{{pk}}".format(name), name="update {}".format(name))
async def update_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)
    if db_model is None:
        raise HTTPException(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)
    return Schemas(data=SchemasResponse(**bool_model.to_dict()))


@router.delete("/{}/{{pk}}".format(name), name="delete {}".format(name))
async def delete_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)
    return Schemas(data=bool_model)


@router.delete("/{}".format(name), name="deletes {}".format(name))
async def delete_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)
    return Schemas(data=bool_model)
```
_7、在根目录下新建文件 **`config.py`**_ 
```python
import os

ROOT_PATH = os.path.dirname(__file__)
# API 接口返回数据
SCHEMAS_SUCCESS_CODE: int = 0
SCHEMAS_SUCCESS_STATUS: str = 'success'
SCHEMAS_SUCCESS_MESSAGE: str = '数据请求成功!'
SCHEMAS_ERROR_CODE: int = 1
SCHEMAS_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_URI
OAUTH_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 = 300
OAUTH_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`**_ 
```gitignore
.idea
Desktop.ini
db.sqlite3
.DS_Store
*__pycache__*
```


### docker 部署
_1、在根目录下新建文件 **`Dockerfile`**_ 
```Dockerfile
FROM python:3.8
WORKDIR /app
EXPOSE 80
RUN mkdir -p /app && pip install lsshu-cms
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80", "--reload"]
```
_2、创建镜像并运行_ 
```shell
docker build -t project_name . && docker run -d --name project_name -v /projects/project_path:/app -p 49000:80 project_name
```
_@project_name 项目名称; /projects/project_path 项目所在的目录; 49000 宿主机端口; 80 容器端口;_

_3、删除容器和镜像_ 
```shell
docker stop project_name && docker rm project_name && docker rmi project_name
```

### nginx 部署
```nginx
http {
    upstream project_server { 
        server 0.0.0.0:49000 weight=1;
    }
    server{
        listen 80;
        server_name project.com;
        index index.html index.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_pass  http://project_server;
          # 配置websocket
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          # 其它代理
          proxy_set_header Http_Referer $http_referer;
          proxy_set_header Host $host:$server_port; 
          proxy_set_header X-real-ip $remote_addr;
        }
        location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|app|main\.py|config\.py)
        {
            return 404;
        }
    }
}
```
_@root /projects/project_path/dist 其中`dist` 可为前端打包的目录;其它根据自身增减_

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/lsshu/fastapi-cms",
    "name": "lsshu-cms",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": "",
    "keywords": "",
    "author": "Lsshu",
    "author_email": "admin@lsshu.cn",
    "download_url": "https://files.pythonhosted.org/packages/55/a5/83278f95eaa0f66f628f8763754404812aebf929722352b639403ac4cf84/lsshu-cms-2.1.0.tar.gz",
    "platform": null,
    "description": "# Lsshu \n_admin@lsshu.cn_\n\n## \u5b89\u88c5\n```shell\npip install lsshu-cms\n```\n\n## \u4f7f\u7528\n_1\u3001\u5728\u9879\u76ee\u6839\u76ee\u5f55\u65b0\u5efa\u6587\u4ef6 **`main.py`**_ \n```python\nfrom fastapi import FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom lsshu.oauth.main import router as router_oauth\n\napp = FastAPI(\n    title='Base API Docs',\n    description='Base API\u63a5\u53e3\u6587\u6863',\n    version='1.0.0'\n)\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"*\"],\n    allow_credentials=True,\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n)\napp.include_router(router_oauth, prefix=\"/api\")\nif __name__ == '__main__':\n    import uvicorn\n\n    uvicorn.run(\"main:app\", host=\"0.0.0.0\", port=8000, reload=True)\n```\n\n_2\u3001\u5728\u9879\u76ee\u6839\u76ee\u5f55\u65b0\u5efapython\u5305 **`app`** \u5728\u5305app\u4e0b\u6253\u5f00\u6587\u4ef6 **`__init__.py`**_ \n```python\nif __name__ == '__main__':\n    from lsshu.oauth.model import Model, Engine\n\n    Model.metadata.create_all(Engine)  # \u521b\u5efa\u8868\u7ed3\u6784\n\n    APP_PERMISSIONS = []\n\n    from config import OAUTH_ADMIN_USERS\n    from lsshu.internal.helpers import store_permissions, init_user_and_password\n\n    store_permissions(APP_PERMISSIONS)  # \u521d\u59cb\u5316\u6743\u9650\n    init_user_and_password(OAUTH_ADMIN_USERS)  # \u521d\u59cb\u5316\u6388\u6743\u7528\u6237\n```\n\n_3\u3001\u5728\u5305app\u4e0b\u65b0\u5efapython\u5305 **`demo`** \u5728\u5305demp\u4e0b\u65b0\u5efa\u6587\u4ef6 **`model.py`**_ \n```python\nfrom sqlalchemy import Column, String\n\nfrom lsshu.internal.db import Model\nfrom lsshu.internal.method import plural\n\nname = plural(__name__.capitalize())\ntable_name = name.replace('.', '_')\npermission = {\"name\": \"Demo\", \"scope\": name, \"action\": [{\"name\": \"de\", \"scope\": \"de\"}]}\n\n\nclass Models(Model):\n    \"\"\" \u6a21\u578b \"\"\"\n    __tablename__ = table_name\n    name = Column(String(15), nullable=False, unique=True, comment=\"\u540d\u79f0\")\n```\n\n_4\u3001\u5728\u5305demo\u4e0b\u65b0\u5efa\u6587\u4ef6 **`crud.py`**_ \n```python\nfrom lsshu.demo.model import Models\nfrom lsshu.internal.crud import BaseCRUD\n\n\nclass CRUD(BaseCRUD):\n    \"\"\"\u8868\u64cd\u4f5c\"\"\"\n    params_model = Models\n```\n\n_5\u3001\u5728\u5305demo\u4e0b\u65b0\u5efa\u6587\u4ef6 **`schema.py`**_ \n```python\nfrom datetime import datetime\nfrom typing import Optional, List\n\nfrom pydantic import BaseModel\n\nfrom lsshu.internal.schema import SchemasPaginate\n\n\nclass SchemasResponse(BaseModel):\n    \"\"\"\u6a21\u578b \u8fd4\u56de\"\"\"\n    id: int\n    name: Optional[str] = None\n    created_at: Optional[datetime] = None\n    updated_at: Optional[datetime] = None\n\n    class Config:\n        orm_mode = True\n\n\nclass SchemasStoreUpdate(BaseModel):\n    \"\"\"\u6a21\u578b \u63d0\u4ea4\"\"\"\n    name: Optional[str] = None\n\n\nclass SchemasPaginateItem(SchemasPaginate):\n    items: List[SchemasResponse]\n\n\nclass SchemasParams(BaseModel):\n    pass\n```\n_6\u3001\u5728\u5305demo\u4e0b\u65b0\u5efa\u6587\u4ef6 **`main.py`**_ \n```python\nfrom typing import List\n\nfrom fastapi import APIRouter, Depends, HTTPException, status, Security\nfrom sqlalchemy.orm import Session\n\nfrom lsshu.internal.db import dbs\nfrom lsshu.internal.depends import model_screen_params, model_post_screen_params, auth_user\nfrom lsshu.internal.schema import ModelScreenParams, Schemas\nfrom lsshu.oauth.user.schema import SchemasOAuthScopes\n\nfrom .crud import CRUD\nfrom .model import name as name\nfrom .schema import SchemasResponse, SchemasParams, SchemasPaginateItem, SchemasStoreUpdate\n\nrouter = APIRouter(tags=[\"Demo\"])\nscopes = [name, ]\n\n\n@router.get('/{}'.format(name), name=\"get {}\".format(name))\nasync def get_models(db: Session = Depends(dbs), params: ModelScreenParams = Depends(model_screen_params),\n                     auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.list\" % name])):\n    \"\"\"\n    :param db:\n    :param params:\n    :param auth:\n    :return:\n    \"\"\"\n    db_model_list = CRUD.paginate(db=db, screen_params=params)\n    return Schemas(data=SchemasPaginateItem(**db_model_list))\n\n\n@router.post('/{}.post'.format(name), name=\"post {}\".format(name))\nasync def post_models(db: Session = Depends(dbs), params: ModelScreenParams = Depends(model_post_screen_params),\n                     auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.list\" % name])):\n    \"\"\"\n    :param db:\n    :param params:\n    :param auth:\n    :return:\n    \"\"\"\n    db_model_list = CRUD.paginate(db=db, screen_params=params)\n    return Schemas(data=SchemasPaginateItem(**db_model_list))\n\n\n@router.get('/{}.params'.format(name), name=\"get {}\".format(name))\nasync def params_models(db: Session = Depends(dbs), auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.list\" % name])):\n    \"\"\"\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n\n    data = {}\n    return Schemas(data=SchemasParams(**data))\n\n\n@router.get('/{}/{{pk}}'.format(name), name=\"get {}\".format(name))\nasync def get_model(pk: int, db: Session = Depends(dbs), auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.get\" % name])):\n    \"\"\"\n    :param pk:\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n    db_model = CRUD.first(db=db, pk=pk)\n    if db_model is None:\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=\"{} not found\".format(name.capitalize()))\n    return Schemas(data=SchemasResponse(**db_model))\n\n\n@router.post('/{}'.format(name), name=\"get {}\".format(name))\nasync def store_model(item: SchemasStoreUpdate, db: Session = Depends(dbs),\n                      auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.store\" % name])):\n    \"\"\"\n    :param item:\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n    db_model = CRUD.first(db=db, where=(\"name\", item.name))\n    if db_model is not None:\n        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,\n                            detail=\"{} already registered\".format(name.capitalize()))\n    bool_model = CRUD.store(db=db, item=item)\n    return Schemas(data=SchemasResponse(**bool_model.to_dict()))\n\n\n@router.put(\"/{}/{{pk}}\".format(name), name=\"update {}\".format(name))\nasync def update_put_model(pk: int, item: SchemasStoreUpdate, db: Session = Depends(dbs),\n                           auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.update\" % name])):\n    \"\"\"\n    :param pk:\n    :param item:\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n    db_model = CRUD.first(db=db, pk=pk)\n    if db_model is None:\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=\"{} not found\".format(name.capitalize()))\n    bool_model = CRUD.update(db=db, pk=pk, item=item)\n    return Schemas(data=SchemasResponse(**bool_model.to_dict()))\n\n\n@router.patch(\"/{}/{{pk}}\".format(name), name=\"update {}\".format(name))\nasync def update_patch_model(pk: int, item: SchemasStoreUpdate, db: Session = Depends(dbs),\n                             auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.update\" % name])):\n    \"\"\"\n    :param pk:\n    :param item:\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n    db_model = CRUD.first(db=db, pk=pk)\n    if db_model is None:\n        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=\"{} not found\".format(name.capitalize()))\n    bool_model = CRUD.update(db=db, pk=pk, item=item, exclude_unset=True)\n    return Schemas(data=SchemasResponse(**bool_model.to_dict()))\n\n\n@router.delete(\"/{}/{{pk}}\".format(name), name=\"delete {}\".format(name))\nasync def delete_model(pk: int, db: Session = Depends(dbs), auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.delete\" % name])):\n    \"\"\"\n    :param pk:\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n    bool_model = CRUD.delete(db=db, pk=pk)\n    return Schemas(data=bool_model)\n\n\n@router.delete(\"/{}\".format(name), name=\"deletes {}\".format(name))\nasync def delete_role_models(pks: List[int], db: Session = Depends(dbs), auth: SchemasOAuthScopes = Security(auth_user, scopes=scopes + [\"%s.delete\" % name])):\n    \"\"\"\n    :param pks:\n    :param db:\n    :param auth:\n    :return:\n    \"\"\"\n    bool_model = CRUD.delete(db=db, pks=pks)\n    return Schemas(data=bool_model)\n```\n_7\u3001\u5728\u6839\u76ee\u5f55\u4e0b\u65b0\u5efa\u6587\u4ef6 **`config.py`**_ \n```python\nimport os\n\nROOT_PATH = os.path.dirname(__file__)\n# API \u63a5\u53e3\u8fd4\u56de\u6570\u636e\nSCHEMAS_SUCCESS_CODE: int = 0\nSCHEMAS_SUCCESS_STATUS: str = 'success'\nSCHEMAS_SUCCESS_MESSAGE: str = '\u6570\u636e\u8bf7\u6c42\u6210\u529f\uff01'\nSCHEMAS_ERROR_CODE: int = 1\nSCHEMAS_ERROR_STATUS: str = 'error'\nSCHEMAS_ERROR_MESSAGE: str = '\u6570\u636e\u8bf7\u6c42\u5931\u8d25\uff01'\n\n# \u7ad9\u70b9\nHOST_URL: str = \"\"\n\n# \u4e0a\u4f20\u76ee\u5f55\nUPLOAD_NAME: str = \"static\"\nUPLOAD_DIR: str = \"static\"\nUPLOAD_URI: str = \"/static\"\n\n# OAuth \u6388\u6743\u76f8\u5173\nOAUTH_DEFAULT_TAGS: list = ['OAuth']\nOAUTH_LOGIN_SCOPES: str = \"login\"\n\nOAUTH_TOKEN_URI: str = \"/token\"\nOAUTH_TOKEN_URL: str = \"/api%s\" % OAUTH_TOKEN_URI\nOAUTH_SCOPES_URI: str = \"/scopes\"\nOAUTH_TOKEN_SCOPES: dict = {\n    OAUTH_LOGIN_SCOPES: OAUTH_LOGIN_SCOPES.capitalize()\n}\nOAUTH_SECRET_KEY: str = \"4a876f7766d1a0e9d97231089be927e38d6dea09233ad212f056b7f1a75cd41d\"\nOAUTH_ALGORITHM: str = \"HS256\"\nOAUTH_ACCESS_TOKEN_EXPIRE_MINUTES: int = 300\nOAUTH_OAUTH_ROUTER: dict = {}\n\n# \u8d85\u7ea7\u7ba1\u7406\u5458 \u8d26\u53f7:\u5bc6\u7801\nOAUTH_ADMIN_USERS: dict = {\n    \"admin\": \"admin\"\n}\n\n# \u6570\u636e\u5e93\u76f8\u5173\nDB_SQLALCHEMY_DATABASE_URL: str = \"sqlite:///{}\".format(os.path.join(ROOT_PATH, 'db.sqlite3'))\n# DB_SQLALCHEMY_DATABASE_URL = \"mysql+pymysql://root:root@192.168.1.3:3306/ic\" # ic \u6570\u636e\u5e93\n\n# echo=True\u8868\u793a\u5f15\u64ce\u5c06\u7528repr()\u51fd\u6570\u8bb0\u5f55\u6240\u6709\u8bed\u53e5\u53ca\u5176\u53c2\u6570\u5217\u8868\u5230\u65e5\u5fd7\n# \u7531\u4e8eSQLAlchemy\u662f\u591a\u7ebf\u7a0b\uff0c\u6307\u5b9acheck_same_thread=False\u6765\u8ba9\u5efa\u7acb\u7684\u5bf9\u8c61\u4efb\u610f\u7ebf\u7a0b\u90fd\u53ef\u4f7f\u7528\u3002\u8fd9\u4e2a\u53c2\u6570\u53ea\u5728\u7528SQLite\u6570\u636e\u5e93\u65f6\u8bbe\u7f6e\nDB_ENGINE_KWARGS: dict = {\n    # \"echo\": True,\n    # \"encoding\": 'utf-8',\n    # \"pool_pre_ping\": True,\n    # \"pool_size\": 100,\n    # \"pool_recycle\": 3600,\n    # \"max_overflow\": 100,\n    \"connect_args\": {\n        'check_same_thread': False,\n        # \"charset\": \"utf8mb4\"\n    }\n}\n# \u5728SQLAlchemy\u4e2d\uff0cCRUD\u90fd\u662f\u901a\u8fc7\u4f1a\u8bdd(session)\u8fdb\u884c\u7684\uff0c\u6240\u4ee5\u6211\u4eec\u5fc5\u987b\u8981\u5148\u521b\u5efa\u4f1a\u8bdd\uff0c\u6bcf\u4e00\u4e2aSessionLocal\u5b9e\u4f8b\u5c31\u662f\u4e00\u4e2a\u6570\u636e\u5e93session\n# flush()\u662f\u6307\u53d1\u9001\u6570\u636e\u5e93\u8bed\u53e5\u5230\u6570\u636e\u5e93\uff0c\u4f46\u6570\u636e\u5e93\u4e0d\u4e00\u5b9a\u6267\u884c\u5199\u5165\u78c1\u76d8\uff1bcommit()\u662f\u6307\u63d0\u4ea4\u4e8b\u52a1\uff0c\u5c06\u53d8\u66f4\u4fdd\u5b58\u5230\u6570\u636e\u5e93\u6587\u4ef6\nDB_SESSION_MAKER_KWARGS: dict = {\n    \"autoflush\": False,\n    \"autocommit\": False,\n    \"expire_on_commit\": True\n}\n```\n\n_8\u3001\u5728\u6839\u76ee\u5f55\u4e0b\u65b0\u5efa\u6587\u4ef6 **`.gitignore`**_ \n```gitignore\n.idea\nDesktop.ini\ndb.sqlite3\n.DS_Store\n*__pycache__*\n```\n\n\n### docker \u90e8\u7f72\n_1\u3001\u5728\u6839\u76ee\u5f55\u4e0b\u65b0\u5efa\u6587\u4ef6 **`Dockerfile`**_ \n```Dockerfile\nFROM python:3.8\nWORKDIR /app\nEXPOSE 80\nRUN mkdir -p /app && pip install lsshu-cms\nCMD [\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"80\", \"--reload\"]\n```\n_2\u3001\u521b\u5efa\u955c\u50cf\u5e76\u8fd0\u884c_ \n```shell\ndocker build -t project_name . && docker run -d --name project_name -v /projects/project_path:/app -p 49000:80 project_name\n```\n_@project_name \u9879\u76ee\u540d\u79f0; /projects/project_path \u9879\u76ee\u6240\u5728\u7684\u76ee\u5f55; 49000 \u5bbf\u4e3b\u673a\u7aef\u53e3; 80 \u5bb9\u5668\u7aef\u53e3;_\n\n_3\u3001\u5220\u9664\u5bb9\u5668\u548c\u955c\u50cf_ \n```shell\ndocker stop project_name && docker rm project_name && docker rmi project_name\n```\n\n### nginx \u90e8\u7f72\n```nginx\nhttp {\n    upstream project_server { \n        server 0.0.0.0:49000 weight=1;\n    }\n    server{\n        listen 80;\n        server_name project.com;\n        index index.html index.htm;\n        root /projects/project_path/dist;\n        \n        try_files $uri $uri/ /index.html;\n        \n        location /static/ {\n          alias /projects/project_path/static/; #\u9759\u6001\u8d44\u6e90\u8def\u5f84\n        }\n        \n        location  ~/api|/docs|/openapi.json\n        {\n          proxy_pass  http://project_server;\n          # \u914d\u7f6ewebsocket\n          proxy_http_version 1.1;\n          proxy_set_header Upgrade $http_upgrade;\n          proxy_set_header Connection \"upgrade\";\n          # \u5176\u5b83\u4ee3\u7406\n          proxy_set_header Http_Referer $http_referer;\n          proxy_set_header Host $host:$server_port; \n          proxy_set_header X-real-ip $remote_addr;\n        }\n        location ~ ^/(\\.user.ini|\\.htaccess|\\.git|\\.svn|\\.project|LICENSE|README.md|app|main\\.py|config\\.py)\n        {\n            return 404;\n        }\n    }\n}\n```\n_@root /projects/project_path/dist \u5176\u4e2d`dist` \u53ef\u4e3a\u524d\u7aef\u6253\u5305\u7684\u76ee\u5f55\uff1b\u5176\u5b83\u6839\u636e\u81ea\u8eab\u589e\u51cf_\n",
    "bugtrack_url": null,
    "license": "GPLv3",
    "summary": "FastAPI \u5f00\u53d1\u7684CMS",
    "version": "2.1.0",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4943df85e1796036fb3ba1a4f3478ac7287ca513ce6ac8bf5265fdcc5f51b72e",
                "md5": "90677d684692951d87e08d772231beb5",
                "sha256": "939d6d563627bffbe0db21c945eccf06147bef8f188fa091cd6e50384aece68d"
            },
            "downloads": -1,
            "filename": "lsshu_cms-2.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "90677d684692951d87e08d772231beb5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 37447,
            "upload_time": "2023-04-06T10:00:56",
            "upload_time_iso_8601": "2023-04-06T10:00:56.410959Z",
            "url": "https://files.pythonhosted.org/packages/49/43/df85e1796036fb3ba1a4f3478ac7287ca513ce6ac8bf5265fdcc5f51b72e/lsshu_cms-2.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "55a583278f95eaa0f66f628f8763754404812aebf929722352b639403ac4cf84",
                "md5": "53ecfbb0f9781ff8e3716489f590eafd",
                "sha256": "19929efafe1c102316f15059a7aebe52a6fbb3c4d9b4cd01b7b8d09a74b3cac2"
            },
            "downloads": -1,
            "filename": "lsshu-cms-2.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "53ecfbb0f9781ff8e3716489f590eafd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 29067,
            "upload_time": "2023-04-06T10:00:59",
            "upload_time_iso_8601": "2023-04-06T10:00:59.007508Z",
            "url": "https://files.pythonhosted.org/packages/55/a5/83278f95eaa0f66f628f8763754404812aebf929722352b639403ac4cf84/lsshu-cms-2.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-04-06 10:00:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "lsshu",
    "github_project": "fastapi-cms",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "lsshu-cms"
}
        
Elapsed time: 0.05416s