Skip to content

后端开发

新建文件夹

在 app/api/v1 下新建文件夹 在 app/api/v1/init.py 中添加你的路由

定义数据结构

在 app/models/system/ 下新建文件, 并且添加到 app/models/system/init.py

如果使用的是Tortoise ORM的其他数据库, 需要添加到你在 app/settings/config.py TORTOISE_ORM 的 apps models下 { "app_book": {"models": ["app.models.book"], "default_connection": "conn_book"} } 需要在 app/models/book/init.py 下能找到你定义的Tortoise ORM Model

在 app/schemas/ 下定义用于接受API请求参数的Pydantic Model Optional 建议替换成 Annotated

python
from typing import Annotated
from pydantic import BaseModel, Field
from app.models.system import StatusType


class BaseApi(BaseModel):
    path: str = Field(title="请求路径", description="/api/v1/auth/login")
    method: str = Field(title="请求方法", description="GET")
    summary: Annotated[str | None, Field(description="API简介")] = None
    tags: Annotated[str | list[str] | None, Field(description="API标签")] = None
    status: Annotated[StatusType | None, Field()] = None

    class Config:
        allow_extra = True  # 允许子类添加其他字段
        populate_by_name = True  # 使用别名来接受参数

定义API

一个增删改查例子

python
from fastapi import APIRouter, Query
from tortoise.expressions import Q

from app.api.v1.utils import insert_log
from app.controllers import user_controller
from app.controllers.api import api_controller
from app.core.ctx import CTX_USER_ID
from app.core.dependency import DependAuth, DependPermission
from app.models.system import Api, Role
from app.models.system import LogType, LogDetailType
from app.schemas.apis import ApiCreate, ApiUpdate
from app.schemas.base import Success, SuccessExtra

router = APIRouter()


@router.get("/apis", summary="查看API列表", dependencies=[DependAuth])
async def _(
        current: int = Query(1, description="页码"),
        size: int = Query(10, description="每页数量"),
        path: str = Query(None, description="API路径"),
        summary: str = Query(None, description="API简介"),
        tags: str = Query(None, description="API模块"),
        status: str = Query(None, description="API状态"),
):
    q = Q()
    if path:
        q &= Q(path__contains=path)
    if summary:
        q &= Q(summary__contains=summary)
    if tags:
        q &= Q(tags__contains=tags.split("|"))
    if status:
        q &= Q(status__contains=status)

    user_id = CTX_USER_ID.get()  # 从请求的token获取用户id
    user_obj = await user_controller.get(id=user_id)
    user_role_objs: list[Role] = await user_obj.roles
    user_role_codes = [role_obj.role_code for role_obj in user_role_objs]
    if "R_SUPER" in user_role_codes:  # 超级管理员具有所有权限
        total, api_objs = await api_controller.list(page=current, page_size=size, search=q, order=["tags", "id"])
    else:
        api_objs: list[Api] = []
        for role_obj in user_role_objs:
            api_objs.extend([api_obj for api_obj in await role_obj.apis])

        unique_apis = list(set(api_objs))
        sorted_menus = sorted(unique_apis, key=lambda x: x.id)
        # 实现分页
        start = (current - 1) * size
        end = start + size
        api_objs = sorted_menus[start:end]
        total = len(sorted_menus)

    records = []
    for obj in api_objs:
        data = await obj.to_dict(exclude_fields=["create_time", "update_time"])
        data["tags"] = "|".join(data["tags"])
        records.append(data)
    data = {"records": records}
    await insert_log(log_type=LogType.UserLog, log_detail_type=LogDetailType.ApiGetList, by_user_id=user_obj.id)
    return SuccessExtra(data=data, total=total, current=current, size=size)


@router.get("/apis/{api_id}", summary="查看API", dependencies=[DependPermission])
async def _(api_id: int):
    api_obj = await api_controller.get(id=api_id)
    data = await api_obj.to_dict(exclude_fields=["id", "create_time", "update_time"])
    await insert_log(log_type=LogType.UserLog, log_detail_type=LogDetailType.ApiGetOne, by_user_id=0)
    return Success(data=data)



@router.post("/apis", summary="创建API", dependencies=[DependPermission])
async def _(
        api_in: ApiCreate,
):
    if isinstance(api_in.tags, str):
        api_in.tags = api_in.tags.split("|")
    new_api = await api_controller.create(obj_in=api_in)
    await insert_log(log_type=LogType.UserLog, log_detail_type=LogDetailType.ApiCreateOne, by_user_id=0)
    return Success(msg="Created Successfully", data={"created_id": new_api.id})


@router.patch("/apis/{api_id}", summary="更新API", dependencies=[DependPermission])
async def _(
        api_id: int,
        api_in: ApiUpdate,
):
    if isinstance(api_in.tags, str):
        api_in.tags = api_in.tags.split("|")
    await api_controller.update(id=api_id, obj_in=api_in)
    await insert_log(log_type=LogType.UserLog, log_detail_type=LogDetailType.ApiUpdateOne, by_user_id=0)
    return Success(msg="Update Successfully", data={"updated_id": api_id})


@router.delete("/apis/{api_id}", summary="删除API", dependencies=[DependPermission])
async def _(
        api_id: int,
):
    await api_controller.remove(id=api_id)
    await insert_log(log_type=LogType.UserLog, log_detail_type=LogDetailType.ApiDeleteOne, by_user_id=0)
    return Success(msg="Deleted Successfully", data={"deleted_id": api_id})


@router.delete("/apis", summary="批量删除API", dependencies=[DependPermission])
async def _(ids: str = Query(..., description="API ID列表, 用逗号隔开")):
    api_ids = ids.split(",")
    deleted_ids = []
    for api_id in api_ids:
        api_obj = await Api.get(id=int(api_id))
        await api_obj.delete()
        deleted_ids.append(int(api_id))
    await insert_log(log_type=LogType.UserLog, log_detail_type=LogDetailType.ApiBatchDelete, by_user_id=0)
    return Success(msg="Deleted Successfully", data={"deleted_ids": deleted_ids})

添加页面和权限

在 系统管理 - 菜单管理 添加你的页面 在 系统管理 - API管理 点击 刷新API 在 系统管理 - 角色管理 编辑 添加角色的菜单权限、按钮权限、API权限

重写刷新即可看到新增页面

根据 MIT 许可证发布