【问题标题】:Flatten or remap model in FastAPI (Pydantic)在 FastAPI (Pydantic) 中展平或重新映射模型
【发布时间】:2023-11-03 07:29:01
【问题描述】:

我在 FastAPI 中设置了一个简单的 API。所以在我的例子中,我有一个 User 表和一个 Article 表。每个用户都可以被分配到多篇文章。没有限制。这意味着,两个表都通过多对多字段链接在一起。

当我打印出所有用户时,会显示如下:

[
  {
    "id": 1,
    "username": "test1",
    "articles": [
      {
        "id": 1,
        "title": "foo",
      },
      {
        "id": 2,
        "title": "bar",
      }
    ],
  },
  {
    "id": 2,
    "username": "test2",
    "articles": [
      {
        "id": 1,
        "title": "foo",
      },
    ],
  },
]

但我希望将文章属性展平。只有文章的 id 应该是可见的,周围没有不需要的字典。

应该是这样的:

[
  {
    "id": 1,
    "username": "test1",
    "articles": [
      1,
      2,
    ],
  },
  {
    "id": 2,
    "username": "test2",
    "articles": [
      1,
    ],
  },
]

我的文件

schemas.py:

class ArticleBase(BaseModel):
    id: int
    title: str

class UserBase(BaseModel):
    id: int
    username: str
    articles: List[ArticleBase]

ma​​in.py:

@app.get("/users/", response_model=List[schemas.UserBase])
def get_users(db: Session = Depends(crud.get_db)):
    return crud.get_users(db)

crud.py:

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

def get_users(db: Session):
    return db.query(models.User).all()

models.py:

user_article_assoc = Table('user_article_assoc', Base.metadata,
                   Column('user_id', Integer, ForeignKey('user.id')),
                   Column('article_id', Integer, ForeignKey('article.id')))

class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String)
    articles = relationship("Article", secondary=user_article_assoc, backref="users")

class Article(Base):
    __tablename__ = "article"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String)

【问题讨论】:

    标签: python fastapi flatten pydantic


    【解决方案1】:

    此代码会将您的用户扁平化为字典列表,您可以轻松修改它以转换为其他模型:

    flatternedUsers = list(map(lambda u: { 'id' :u.id, 'username': u.username, 'articles': list(map(operator.attrgetter('id'), u.articles)) }, users))
    

    您也可以为此使用对象-对象映射器库,例如object-mapperodin。对象-对象映射器的好处是,如果您的用户现在有一个新属性,例如birthdate 它将自动映射到您要返回的扁平化用户模型中的相同属性,假设您没有忘记向它们添加 birthdate 属性。

    【讨论】: