# cameo **Repository Path**: croonyy/cameo ## Basic Information - **Project Name**: cameo - **Description**: cameo是一个开源项目(fastapi-admin/fastapiadmin/fastapi_admin),用于帮助开发者快速搭建fastapi项目,并且自带了一个admin应用(前后端分离),参考django-admin设计,使用tortoise-orm作为数据库操作框架,支持mysql,sqlite,postgresql,等多种数据库,实现RBAC权限管理模式。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 2 - **Created**: 2025-06-25 - **Last Updated**: 2026-03-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Cameo

FastAPI

## 介绍 cameo是一个开源项目(fastapi-admin/fastapiadmin/fastapi_admin),用于帮助开发者快速搭建fastapi项目,并且自带了一个admin应用(前后端分离,前端使用vue3的开源框架naive-ui-admin),参考django-admin设计,使用tortoise-orm作为数据库操作框架,支持mysql,sqlite,postgresql等多种数据库,实现RBAC权限管理模式,增删改查api自动生成。 ## 项目地址 - [__github__ https://github.com/croonyy/cameo](https://github.com/croonyy/cameo) - [__gitee__ https://gitee.com/croonyy/cameo](https://gitee.com/croonyy/cameo) ## 版本依赖 - __python__ --version:3.13.0 - __vue3__ - __Node__ -v:v22.14.0 - __npm__ -version:10.9.2 ## 安装教程 前后端依赖安装 ```bash # 事先安装python3.13 # 克隆源码 git clone https://gitee.com/croonyy/cameo.git # 进入到项目目录 cd cameo # 安装python环境依赖,如果依赖下载慢,请自行更换pip镜像源 pip install -r requirements.txt # 初始化数据库 aerich upgrade #执行脚本,创建admin用户(密码可后续自行更改),和模型权限 python init_data.py # 前端安装 # 进入到/front目录 cd front pnpm install ``` ## 运行 ```bash # 1、运行后端服务 # 如果是python虚拟环境,请先激活虚拟环境 conda activate [python_env_name] # 进入到项目目录下,执行 python run.py # 2、运行前端服务 # 进入到前端目录下 cd front pnpm run dev # 3、访问 # 访问后端接口文档 http://localhost:3014/udadmin/docs # 访问前端页面 http://localhost:1992/ # 登录账号/密码,预置两个用户,一个管理员和一个普通用户,可自行编辑用户修改密码 admin/admin test_user/123456 ``` ## 项目图片展示 ###### 接口文档 ![api_doc](static/images/api_doc.png) ###### 控制台 ![console](static/images/console.png) ###### 用户列表 ![user](static/images/user.png) ###### 编辑用户 ![edit_user](static/images/edit_user.png) ###### 权限实例 ![permission](static/images/permission.png) ###### 编辑权限 ![edit_permission](static/images/edit_permission.png) ###### 创建角色 ![create_role](static/images/create_role.png) ## 项目结构 ```shell ├── apps # app目录,推荐一个app创建一个文件夹,可参考源码样例,也可自行组织app代码结构 ├── app1 # 样例app ├── ... ├── udadmin # admin应用 ├── ... ├── config ├── settings.py # 项目配置文件 ├── db ├── db.sqlite3 # 默认数据库为sqlite3,此为数据库文件 ├── init ├── front # 前端根目录 ├── ... ├── migrations # 数据库迁移文件,如若更换数据库,需要重新生成 ├── app1 # 一个app会生成一个文件夹 ├── udadmin ├── notes # 笔记 ├── ... ├── static # 静态文件 ├── docs-ui # 为了swagger文档从本地加载,文件本地化 ├── images # 项目展示图片 ├── favicon.ico ├── test # 测试代码 ├── ... ├── tools # 工具代码 ├── locate_print.py ├── objdoc.py ├── timer.py ├── .gitignore ├── cert.pem ├── init_data.py # 初始化数据库的用户和权限的脚本 ├── key.pem ├── main.py ├── pyproject.toml ├── README.en.md ├── README.md ├── requirements.txt # python环境依赖 ├── run.py # 主入口,python run.py 启动项目 ├── vscode_extensions.txt # vscode 插件 ``` ## 使用说明 #### 请按步骤参考样例app1,熟悉步骤之后可删除app1目录,并创建自己的app 1. apps目录下创建app1(可随意命名,但请勿使用udadmin,udadmin是admin应用目录)目录 2. 创建app1/app.py,定义app应用 ```python app = FastAPI( # root_path="/test", title="app1", version="1.0.0", swagger_ui_oauth2_redirect_url="/docs/oauth2-redirect", servers=[{"url": "http://localhost:1002", "description": "test"}], description='', # docs_url="/docs", debug=True, openapi_tags=openapi_tags, ) ``` 在主app上挂载子app也就是app1应用,参考main.py代码 ```python # 上下文管理,startup执行yield之前的代码,shutdown执行yield以下的代码 @asynccontextmanager async def lifespan(app: FastAPI): # 传递 TORTOISE_ORM 配置给 Tortoise.init() await Tortoise.init(config=TORTOISE_ORM) # 确保所有的模型都被创建(如果需要),取消注释项目启动会自己创建, # 也可以用aerich init-db生成迁移文件并创建,或者用迁移文件aerich upgrade创建。 # await Tortoise.generate_schemas() # 初始化数据库配置后,再注册模型,不然会找不到模型的app属性(因为app属性是在数据库init里面设置的) # 挂载app,也要在数据库配置初始化之后,才能有模型的app名称 # 先从数据库获取信息配置,再挂载app(app里面会注册模型,才能拿到配置信息) from apps.udadmin.app import app as admin_app from apps.app1.app import app as app1 app.mount("/udadmin", admin_app, name="admin") app.mount("/app1", app1, name="app1") from apps.udadmin.utils.model_register import mr print(f"registered models:\n{list(mr.models_info.keys())}") yield try: # 销毁fastapi实例后断开数据库连接 await Tortoise.close_connections() except Exception as e: print("="*80) print(e) ``` 3. 创建app1/models.py,在app1/models.py里面定义模型 ```python class TestModel(Model): id = fields.IntField( pk=True, auto_increment=True, description="主键id", ud_name="序号" ) big_int_field = fields.BigIntField() binary_field = fields.BinaryField() boolean_field = fields.BooleanField(ud_name="布尔类型") char_enum_field = fields.CharEnumField(enums.TestEnum, description="测试枚举") char_field = fields.CharField(max_length=255, description="字符串类型") date_field = fields.DateField(description="日期类型") date_time_field = fields.DatetimeField(description="日期时间类型") decimal_field = fields.DecimalField(max_digits=10, decimal_places=2, description="小数类型") float_field = fields.FloatField() int_enum_field = fields.IntEnumField( enum_type=IntEnum("IntTestEnum", {"选项1": 1, "选项2": 2, "选项3": 3}) ) int_field = fields.IntField() json_field = fields.JSONField() small_integer_field = fields.SmallIntField() text_field = fields.TextField() time_delta_field = fields.TimeDeltaField() uuid_field = fields.UUIDField() def __str__(self) -> str: return f"<{self.__class__.__name__}: {self.id}>" class Meta: menu_name = "test模型" table_description = "测试模型" ``` - 定义字段的时候可以加入ud_name属性,ud_name字段为前端显示字段名称,默认为字段名称,如果定义了ud_name,则前端显示ud_name字段名称 - 定义字段的时候可以加入ud_order属性,ud_order属性为前端显示字段排序,默认为999,数字越小越靠前 - 模型的 __\_\_str\_\___ 方法为模型显示名称(一般是关系名称,多对多,一对多时候显示的名称),可定义,不定义则默认为模型名称 - class Meta里面定义menu_name为前端菜单名称,table_description为前端模型描述,都可选,不填则默认为模型名称 ```sh # 迁移到数据库 # 命令行执行 aerich migrate # 生成模型修改的迁移文件 aerich upgrade # 应用迁移文件到数据库 ``` 4. 创建app1/ui.py,定义前端模型显示配置 ```python from apps.udadmin.utils.ui_tools import UiInfo from . import models as md TestModelUi = UiInfo( model=md.TestModel, list_display=[ "id", "big_int_field", "binary_field", "boolean_field", ], list_filter=[ "id", "big_int_field", "binary_field", "boolean_field", "char_enum_field", "char_field", "date_field", "date_time_field", "decimal_field", "float_field", "int_enum_field", "int_field", "json_field", "small_integer_field", "text_field", "time_delta_field", "uuid_field", ], search_fields=[ "char_field", ], ) ``` - model为模型类 - list_display为列表显示字段,默认为所有字段,可以不定义 - list_filter为列表过滤字段,默认为空 - search_fields为搜索字段,默认为空 - 其他配置请参考udadmin.ui.UiInfo 定义 5. 在app1/app.py注册模型和ui配置 ```python from apps.udadmin.utils.model_register import mr from apps.app1 import models as md from apps.app1 import ui mr.register(app, md.TestModel, ui_info=ui.TestModelUi) ``` - app为app1/app.py定义的app实例 - md.TestModel为app1/models.py定义的模型类 - ui_info为app1/ui.py定义的ui配置 6. 如果需要开发其他api,可在app1目录下创建view文件夹(推荐),或者自行组织文件结构书写代码定义接口 ###### 上述步骤结束后,前端会自动生成模型的增删改查页面,管理员可直接看到,其他用户需要定义权限(前端页面【认证与授权/权限实例模型】里面定义)并赋权才看得到,权限格式参考admin应用已有的模型权限 ## 生产部署 #### 1.前端 打包前端,进入到/front 目录下执行: ```bash pnpm run build ``` 命令执行完后会在/front目录生成一个 __dist__ 文件夹,里面就是打包好的所有前端代码文件 静态文件部署可使用本项目的后端服务,或者更好的使用 nginx 静态文件服务 ##### (方式一)使用本项目后端服务: 因为后端已经启用了静态文件服务,/main.py里面的静态文件服务配置如下 ```python ... # 挂载静态文件服务 app.mount( "/static", StaticFiles(directory=os.path.join(BASE_DIR, "static"), html=True), name="static", ) ... # 重定向 @app.get("/") async def index(): return RedirectResponse(url="/admin") # # 前端入口 # 所有admin应用的路由都要定位到前端主页 # 捕获所有其他路径并返回 index.html @app.get("/admin/{full_path:path}", response_class=HTMLResponse) async def catch_all(request: Request, full_path: str): return templates.TemplateResponse("/dist/index.html", {"request": request}) ``` 所以生产环境只需要将dist文件夹放到/static下,并修改 __/static/dist/app.config.js__ 文件里面的 __VITE_GLOB_API_URL_PREFIX__ 的值为你的后端服务的根路径(此步骤也可在打包前修改/front/.env.production 里面的VITE_GLOB_API_URL_PREFIX值来实现) ```js // 文件 /static/dist/app.config.js window.__PRODUCTION__CAMEO__CONF__={ "VITE_GLOB_APP_TITLE":"Cameo", "VITE_GLOB_APP_SHORT_NAME":"Cameo", "VITE_GLOB_API_URL":"", "VITE_GLOB_API_URL_PREFIX":"http://localhost:3014", "VITE_GLOB_UPLOAD_URL":"", "VITE_GLOB_IMG_URL":""}; Object.freeze(window.__PRODUCTION__CAMEO__CONF__); Object.defineProperty(window,"__PRODUCTION__CAMEO__CONF__",{configurable:false,writable:false,}); ``` 然后正常访问后端服务地址,即可访问前端页面 ##### (方式二)使用nginx: 步骤类似上述方式,只是用nginx做静态资源服务,配置好以下两个路由(nginx语法来实现下述表述): - nginx的 __/admin/...full_path...__ 路由到 /static/dist/index.html文件 - nginx的 __/static/...full_path...__ 路由到 /static/dist/...full_path...文件 ```nginx server { listen 80; server_name yourdomain.com; root /path/to/your/webroot; # 替换为你的实际路径 # 处理 /static/ 下的静态文件请求 location /static/ { alias /path/to/your/dist/; # 指向 dist 目录 try_files $uri $uri/ =404; # 可选:设置缓存头 expires 7d; access_log off; } # 处理 /admin/ 下的所有路由(前端路由) location /admin/ { alias /path/to/your/dist/; # 同样指向 dist 目录 try_files $uri $uri/ /index.html; # 如果你的前端入口文件是 index.html(在 dist 目录下) # 可以这样写: # try_files $uri $uri/ /dist/index.html; } # 可选:处理根路径或其他路由 location / { try_files $uri $uri/ /index.html; } # 其他配置(如 gzip、SSL 等)... } ``` #### 2.后端 后端启动 ```shell python run.py ``` 可以使用nohup命令后台运行 修改生产配置/run.py文件里面的run_server方法中的uvicorn.run函数的参数 ```python ... def run_server(): uvicorn.run("main:app", host="localhost", port=3014, reload=True) ... # 还可以增加启动参数,请参考uvicorn.run的参数说明 ``` ## 关于RBAC权限管理系统 __udadmin__ 应用的模型权限 __权限实例__ 已经由 init_data.py 脚本生成,自定义应用创建的模型需要手动创建权限实例,参考 udadmin已有的权限实例在ui界面上来创建,定义的权限实例可以由 __角色__ (可在角色管理模型里面新建)带给用户,也可以直接赋予用户,具体请参考项目里面的 __认证与授权__ 模块的模型 # 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request