如何在PostgreSQL的Tortoise-ORM中正确使用ArrayField并实现FastAPI-admin的CRUD
问题原因
FastAPI-admin对ArrayField的默认输入处理逻辑存在问题:当你在表单中输入单个字符串(比如#abcd)时,它会将字符串视为可迭代的字符序列,自动把每个字符拆分成数组的独立元素,而非将整个字符串作为数组的单个元素存入数据库。而直接用Postico操作时,你是明确传入了数组格式的参数(比如{"#abcd"}),所以数据库能正确识别。
Tortoise-ORM的ArrayField(element_type="text")定义本身是正确的,问题出在FastAPI-admin的前端输入解析和后台处理环节。
解决方法
1. 规范Tortoise-ORM模型定义
模型定义可以保持原写法,也可以用更明确的字段类型声明:
from tortoise.models import Model from tortoise.fields import ArrayField, TextField class YourModel(Model): # 两种写法都有效,推荐用TextField()更直观 hashtag = ArrayField(element_type=TextField(), null=True) # 原写法:hashtag = ArrayField(element_type="text")
2. 自定义FastAPI-admin表单处理逻辑
通过重写模型管理类的创建/更新前置方法,将前端输入转换成正确的数组格式,这里提供两种常用方案:
方案一:逗号分隔输入(用户友好)
让用户输入逗号分隔的标签,后台自动拆分转成数组:
from fastapi_admin.app import app from fastapi_admin.widgets import TextInput @app.register(YourModel) class YourModelAdmin: fields = [YourModel.hashtag] form_fields = { "hashtag": TextInput( label="话题标签", placeholder="输入逗号分隔的标签,比如#abcd,#wxyz" ) } # 创建前处理输入 async def before_create(self, obj: dict, request): if obj.get("hashtag"): # 按逗号拆分并去除每个标签的前后空格 obj["hashtag"] = [tag.strip() for tag in obj["hashtag"].split(",")] return obj # 更新前处理输入 async def before_update(self, obj: dict, request): if obj.get("hashtag"): obj["hashtag"] = [tag.strip() for tag in obj["hashtag"].split(",")] return obj
方案二:JSON格式输入(精准可控)
让用户输入标准JSON数组格式,后台解析成数组:
from fastapi_admin.app import app from fastapi_admin.widgets import TextArea import json @app.register(YourModel) class YourModelAdmin: fields = [YourModel.hashtag] form_fields = { "hashtag": TextArea( label="话题标签", placeholder='输入JSON格式数组,比如["#abcd", "#wxyz"]' ) } async def before_create(self, obj: dict, request): if obj.get("hashtag"): try: obj["hashtag"] = json.loads(obj["hashtag"]) except json.JSONDecodeError: # 解析失败时,将输入内容作为单个元素存入数组 obj["hashtag"] = [obj["hashtag"].strip()] return obj async def before_update(self, obj: dict, request): if obj.get("hashtag"): try: obj["hashtag"] = json.loads(obj["hashtag"]) except json.JSONDecodeError: obj["hashtag"] = [obj["hashtag"].strip()] return obj
3. 配套FastAPI接口的Pydantic验证
如果是通过FastAPI接口直接提交数据,需要在Pydantic模型中明确声明数组类型,避免参数解析错误:
from pydantic import BaseModel from typing import List, Optional class YourModelCreate(BaseModel): hashtag: Optional[List[str]] = None # 在FastAPI路由中使用该模型 @app.post("/your-model/create") async def create_model_item(item: YourModelCreate): await YourModel.create(**item.dict()) return {"status": "success"}
内容的提问来源于stack exchange,提问作者Shashank Raj
相关产品推荐
相关产品推荐

