Jua*_*ejo 3 sqlalchemy pydantic fastapi sqlmodel
我正在使用FastAPI制作我的个人投资组合 API ,并决定尝试SQLModel。它感觉非常直观,到目前为止我很喜欢它,但我遇到了一个问题,我已经挣扎了好几天,试图了解如何解决它。
\n我有一个项目模型:
\nfrom datetime import datetime\nfrom typing import List, Optional, Set\nfrom sqlmodel import SQLModel, Field\n\n\nclass ProjectBase(SQLModel):\n    name: Optional[str]\n    summary: Optional[str]\n    description: Optional[str]\n    category: Set[str] = ()\n    award: Optional[str] = None\n    url: Optional[str] = None\n    published: datetime = datetime.utcnow()\n    image: str = "placeholderMainImage"\n    images: List[str] = []\n    learning: Optional[str]\n    tech: Optional[str]\n    tools: Optional[str]\n\n\n\nclass Project(ProjectBase, table=True):\n    id: int = Field(default=None, primary_key=True)\n    created_at: datetime = Field(default_factory=datetime.utcnow)\n    updated_at: datetime = Field(default_factory=datetime.utcnow)\nFastAPI 工作正常,我检查了 localhost:8000/docs并正确进行了类型验证:
\n    {\n  "name": "string",\n  "summary": "string",\n  "description": "string",\n  "category": [],\n  "award": "string",\n  "url": "string",\n  "published": "2021-10-04T20:43:26.472364",\n  "image": "placeholderMainImage",\n  "images": [],\n  "learning": "string",\n  "tech": "string",\n  "tools": "string",\n  "id": 0,\n  "created_at": "2021-10-04T21:01:30.048Z",\n  "updated_at": "2021-10-04T21:01:30.048Z"\n}\n当我使用上述查询发出 POST 请求时,出现内部服务器错误:
\ninvalid input for query argument $4: (expected str, got set)\n不幸的是,SQLModel 在设计上会在创建表时将任何奇怪的类型转换为 VARCHAR,从而无法使用 List 或 Set 功能:
\n   CREATE TABLE project (\n         name VARCHAR, \n         summary VARCHAR, \n         description VARCHAR, \n         category VARCHAR, \n         award VARCHAR, \n         url VARCHAR, \n         published TIMESTAMP WITHOUT TIME ZONE, \n         image VARCHAR, \n         images VARCHAR, \n         learning VARCHAR, \n         tech VARCHAR, \n         tools VARCHAR, \n         id SERIAL, \n        created_at TIMESTAMP WITHOUT TIME ZONE, \n        updated_at TIMESTAMP WITHOUT TIME ZONE, \n        PRIMARY KEY (id)\n )\n我知道 postgres 有一些数组类型,例如:integer[]和text[],它们可以处理类别和图像字段的这种情况。\n尝试手动更改表列类型,结果相同。
\n尝试将类别和图像发布为 str:
\n    {\n  "detail": [\n    {\n      "loc": [\n        "body",\n        "category"\n      ],\n      "msg": "value is not a valid set",\n      "type": "type_error.set"\n    },\n    {\n      "loc": [\n        "body",\n        "images"\n      ],\n      "msg": "value is not a valid list",\n      "type": "type_error.list"\n    }\n  ]\n}\n如果无法使用如此出色的功能来清理我收到的数据,那将是非常遗憾的。我在互联网上查找,但找不到任何相关内容或使用 List 和 Set 与 SQLModel 的示例
\n\xc2\xbf我可以做什么来支持这种情况?
\nPD:我也在使用 asyncpg
\n我让它适用于列表,但不适用于 postgres 数据库上的集合。问题在于结果何时映射回您的项目类。这是我的完整代码。
from datetime import datetime
from typing import List, Optional, Set
from sqlalchemy.sql.schema import Column
from sqlmodel import SQLModel, Field, create_engine, Session, select, String, ARRAY 
from fastapi import FastAPI
class ProjectBase(SQLModel):
    name: Optional[str]
    category: Set[str] = Field(default=None, sa_column=Column(ARRAY(String())))
    images: List[str] = Field(default=None, sa_column=Column(ARRAY(String())))
class Project(ProjectBase, table=True):
    id: int = Field(default=None, primary_key=True)
engine = create_engine("postgresql://postgres:mysecretpassword@localhost:5432/testdb")
new_proj = Project(
    name=f"{str(datetime.time(datetime.utcnow()))}", 
    category=("hi", "hello", "cat3"), 
    images=["img1", "img2"] 
)
app = FastAPI()
@app.on_event("startup")
def on_startup():
    SQLModel.metadata.create_all(engine)
    print("BEFORE REFRESH:", new_proj)
    with Session(engine) as session:
        session.add(new_proj)
        session.commit()
        session.refresh(new_proj)
    print("AFTER REFRESH:", new_proj)
@app.get("/", response_model=List[Project])
def home():
    with Session(engine) as session:
        projects = session.exec(select(Project)).all()
        return projects
我对你的Project课程进行了一些简化。启动 uvicorn 运行此程序后,我得到以下输出(参考@app.on_event("startup")):
BEFORE REFRESH: name='17:17:38.090595' category={'hoi', 'cat3', 'hello'} images=['img1', 'img2'] id=None
AFTER REFRESH: id=7 category=['hoi', 'cat3', 'hello'] images=['img1', 'img2'] name='17:17:38.090595'
注意category值的区别,从数据库刷新对象之前以 { 开头(表示集合),从数据库刷新对象之后以 [ 开头。
我尝试了各种方法但没有效果。我唯一能想到的(但找不到任何相关内容)是某种自定义映射规则sqlalchemy。尽管我对该软件包了解不够,但无法真正理解我在寻找什么。希望这至少有帮助!无论哪种方式我都学到了很多:)
| 归档时间: | 
 | 
| 查看次数: | 2585 次 | 
| 最近记录: |