项目地址:https://github.com/mizhexiaoxiao/vue-fastapi-admin
本次笔记的目的是模仿项目原本的fastapi接口写一个自定义的api,仅供参考。
本项目数据库使用的是tortoise库来实现增删改查,因为基本等于自用所以写的比较糙。
第一步:定义model,放在app/models文件夹下。注意,需要在init.py中引入对应的py文件
from datetime import datetime
from typing import List, Optional, Dict, Any, Type, TypeVar, Union
from tortoise.models import Model
from tortoise import fields, Tortoise
from pydantic import BaseModel
# ========== 禁用词模型定义 ==========
class BanWordsTag(Model):
id = fields.IntField(pk=True)
tag = fields.CharField(max_length=255, unique=True) # 标签内容
tag_type = fields.CharField(max_length=20) # 标签类型:'infringing' 或 'sensitive'
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True)
class Meta:
table = "ban_words_tag"
def serialize_leaf(self, leaf):
# 这里根据实际情况来转换 leaf
if isinstance(leaf, dict):
return leaf
return str(leaf) # 如果无法直接序列化,可以转成字符串
def to_dict(self):
return {
"id": self.id,
"tag": self.tag,
"tag_type": self.tag_type,
}
# ========== Pydantic Schema 定义 ==========
class TagBase(BaseModel):
tag: str
tag_type: str # 必须是 'infringing' 或 'sensitive'
class Config:
orm_mode = True
class TagCreate(TagBase):
pass
class TagUpdate(BaseModel):
tag: Optional[str] = None
tag_type: Optional[str] = None
class TagResponse(TagBase):
id: int
created_at: datetime
updated_at: datetime
第二步,编写control,放在app/controllers文件夹下,同样的,需要再init文件中声明
# ========== TagController ==========
from typing import List
from app.core.crud import CRUDBase
from app.models.mj_models import BanWordsTag, TagCreate, TagUpdate
from tortoise.contrib.pydantic import pydantic_model_creator
class TagController(CRUDBase[BanWordsTag, TagCreate, TagUpdate]):
def __init__(self):
super().__init__(model=BanWordsTag)
async def get_by_type(self, tag_type: str) -> List[BanWordsTag]:
return await self.model.filter(tag_type=tag_type).all()
async def delete_by_tag(self, tag: str) -> None:
obj = await self.model.filter(tag=tag).first()
if obj:
await obj.delete()
async def create_if_not_exists(self, tag: str, tag_type: str) -> BanWordsTag:
# 查找是否已经有这个标签
existing_tag = await self.model.filter(tag=tag).first()
if existing_tag:
print(f"标签 '{tag}' 已存在,跳过创建。")
return existing_tag
# 如果没有,则创建新的标签
return await self.create(TagCreate(tag=tag, tag_type=tag_type))
# 单例模式,方便外部引用
tag_controller = TagController()
第三步,创建一个路由文件,放在app/api/v1目录下,init.py参考其他文件写法
import logging
from fastapi import APIRouter, Query, HTTPException
from tortoise.expressions import Q
from app.controllers import tag_controller
from app.models import TagCreate
from app.schemas.base import Success, SuccessExtra
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/list", summary="查看标签列表")
async def list_tags(
page: int = Query(1, description="页码"),
page_size: int = Query(10, description="每页数量"),
tag_name: str = Query("", description="标签名称,用于查询"),
tag_type: str = Query(default="infringing", description="标签类型,用于查询,必须是 'infringing' 或 'sensitive'")
# 可选查询条件
):
q = Q()
if tag_name:
q &= Q(tag__contains=tag_name)
if tag_type:
q &= Q(tag_type=tag_type)
total, tag_objs = await tag_controller.list(page=page, page_size=page_size, search=q)
data = [obj.to_dict() for obj in tag_objs]
return SuccessExtra(data=data, total=total, page=page, page_size=page_size)
@router.get("/get", summary="查看标签")
async def get_tag(
tag_id: int = Query(..., description="标签ID")
):
tag_obj = await tag_controller.get(id=tag_id)
return Success(data=tag_obj.to_dict())
@router.post("/create", summary="创建标签")
async def create_tag(
tag_create: TagCreate # 假设你有一个 TagCreate Schema 用于创建
):
# 使用 Controller 的方法来创建标签
created_tag = await tag_controller.create(tag_create)
return Success(data=await created_tag.to_dict())
@router.delete("/delete", summary="删除标签")
async def delete_tag(
tag_id: int = Query(..., description="标签ID")
):
tag_obj = tag_controller.get(id=tag_id)
if not tag_obj:
raise HTTPException(status_code=404, detail="标签未找到")
await tag_controller.remove(tag_id)
return Success(data={"message": "标签已成功删除"})
最后,在app/controllers/__init__.py中添加:
v1_router.include_router(mj_api_router,prefix='/mj',dependencies=[DependPermisson])
就成功添加了几个新的带鉴权的路由,如图所示: