使用 FastAPI 从获取请求中添加更多数据
Add more data from a get request with FastAPI
我开始在 python 和 sqlalchemy 中使用 FastAPI 构建一个 api :
这是模型的一部分:
class Game(Base):
__tablename__ = "games"
id = Column(Integer, primary_key=True, index=True)
league_id = Column(Integer)
radiant_score = Column(Integer)
dire_score = Column(Integer)
duration = Column(Integer)
is_valid = Column(Boolean, default=True)
playerstats = relationship("PlayerStat", back_populates="match")
class PlayerStat(Base):
__tablename__ = "playerstats"
match_id = Column(Integer, ForeignKey("games.id"), primary_key=True)
slot = Column(Integer, primary_key=True)
hero_id = Column(Integer, ForeignKey("heros.id"))
num_kills = Column(Integer, default=None)
isRadiant = Column(Boolean, default=None)
match = relationship("Game", back_populates="playerstats")
heros = relationship("Hero", back_populates="playerstats")
在此之后,我为 pydantic 创建了 schemas/models(很长的部分很抱歉):
class PlayerStatBase(BaseModel):
slot: int
hero_id: int
num_kills: int
isRadiant: bool
class PlayerStatCreate(PlayerStatBase):
pass
class PlayerStat(PlayerStatBase):
slot: int
hero_id: int
num_kills: int
isRadiant: bool
class Config:
orm_mode = True
class GameBase(BaseModel):
id: int
league_id: int
radiant_score: int
dire_score: int
duration: int
is_valid: bool
class GameCreate(GameBase):
pass
class Game(GameBase):
id: int
league_id: int
radiant_score: int
dire_score: int
duration: int
is_valid: bool
players: List[PlayerStat] = [{}]
class Config:
orm_mode = True
以及我在 api 中使用的 crud 函数:
def get_match(db: Session, match_id: int):
print(db.query(models.Game).filter(models.Game.id == match_id))
return db.query(models.Game).filter(models.Game.id == match_id).first()
api 路线是:
@app.get("/matches/{match_id}", response_model=schemas.Game)
def read_game(match_id: int, db: Session = Depends(get_db)):
db_game = crud.get_match(db, match_id=match_id)
if db_game is None:
raise HTTPException(status_code=404, detail="Game not found")
return db_game
我得到的结果是下一个:
{
"id": 1,
"league_id": 10,
"radiant_score": 41,
"dire_score": 5,
"duration": 3541,
"is_valid": true,
"players": [
{}
]
}
我想用相应比赛的球员统计列表(按时段排序)填充“球员”,如:
"players" : [
{
"slot": 0,
"hero_id": 14,
"num_kills": 54,
"isRadiant": true
},
{
"slot": 1,
"hero_id": 15,
"num_kills": 1,
"isRadiant": false
}
]
我想我需要尝试 model/schema 或 crud 函数之一,但真的不知道是哪一个?
另外,也许有一些无用或构建不佳的 pydantic 模式
PS : 我遵循了 FastAPI 文档的指南(我建议阅读)。
感谢您的帮助!
我相信你的问题不在fastapi的范围内,而是在sqlalchemy的范围内。 当您查询具有关系的 orm 对象时,fastapi 的标准是在访问它们时延迟加载关系。由于您从不直接访问关系 playerstats,因此它不会加载。参见 the docs 获取信息。
您的问题的解决方案应该是将 crud 函数更新为:
return db.query(models.Game).filter(models.Game.id == match_id)
.options(selectinload(models.Game.playerstats)).first()
"Select In Load" 是一种预加载类型,它将在提交查询时加载关系。如果您希望在每次查询时都出现这种行为,您可以将 orm 更新为:
playerstats = relationship("PlayerStat", back_populates="match", lazy="selectin")
希望对您有所帮助。这是我在 Whosebug 上的第一个答案 :)
编辑:实际上还有另一件事。在您的 orm 中,这种关系称为“playerstats”,而您在 pydantic 模型中将属性命名为“players”。那是行不通的。将 pydantic 属性名称从“players”更改为“playerstats”,现在一切正常。
编辑 2:正如您所猜测的那样,目前还不能一切正常。我刚刚看到还缺少另一件事。在 pydantic 模型中,您可以设置 orm 选项。这在使用 sqlalchemy 时非常重要。我向您所有的 pydantic 模型推荐这个。 这必须在每个 pydantic 模型及其属性模型上设置
class OtherModel(BaseModel):
value: str = None
class Config:
orm_mode = True
class SomePydanticModel(BaseModel):
value: str = None
some_other_model: OtherModel = None
class Config:
orm_mode = True
现在我们也可以再次修改你的crud方法的return语句:
return Game.from_orm(db.query(models.Game).options(selectinload(models.Game.playerstats)).filter(models.Game.id == match_id).first())
现在终于一切正常了:)
我开始在 python 和 sqlalchemy 中使用 FastAPI 构建一个 api : 这是模型的一部分:
class Game(Base):
__tablename__ = "games"
id = Column(Integer, primary_key=True, index=True)
league_id = Column(Integer)
radiant_score = Column(Integer)
dire_score = Column(Integer)
duration = Column(Integer)
is_valid = Column(Boolean, default=True)
playerstats = relationship("PlayerStat", back_populates="match")
class PlayerStat(Base):
__tablename__ = "playerstats"
match_id = Column(Integer, ForeignKey("games.id"), primary_key=True)
slot = Column(Integer, primary_key=True)
hero_id = Column(Integer, ForeignKey("heros.id"))
num_kills = Column(Integer, default=None)
isRadiant = Column(Boolean, default=None)
match = relationship("Game", back_populates="playerstats")
heros = relationship("Hero", back_populates="playerstats")
在此之后,我为 pydantic 创建了 schemas/models(很长的部分很抱歉):
class PlayerStatBase(BaseModel):
slot: int
hero_id: int
num_kills: int
isRadiant: bool
class PlayerStatCreate(PlayerStatBase):
pass
class PlayerStat(PlayerStatBase):
slot: int
hero_id: int
num_kills: int
isRadiant: bool
class Config:
orm_mode = True
class GameBase(BaseModel):
id: int
league_id: int
radiant_score: int
dire_score: int
duration: int
is_valid: bool
class GameCreate(GameBase):
pass
class Game(GameBase):
id: int
league_id: int
radiant_score: int
dire_score: int
duration: int
is_valid: bool
players: List[PlayerStat] = [{}]
class Config:
orm_mode = True
以及我在 api 中使用的 crud 函数:
def get_match(db: Session, match_id: int):
print(db.query(models.Game).filter(models.Game.id == match_id))
return db.query(models.Game).filter(models.Game.id == match_id).first()
api 路线是:
@app.get("/matches/{match_id}", response_model=schemas.Game)
def read_game(match_id: int, db: Session = Depends(get_db)):
db_game = crud.get_match(db, match_id=match_id)
if db_game is None:
raise HTTPException(status_code=404, detail="Game not found")
return db_game
我得到的结果是下一个:
{
"id": 1,
"league_id": 10,
"radiant_score": 41,
"dire_score": 5,
"duration": 3541,
"is_valid": true,
"players": [
{}
]
}
我想用相应比赛的球员统计列表(按时段排序)填充“球员”,如:
"players" : [
{
"slot": 0,
"hero_id": 14,
"num_kills": 54,
"isRadiant": true
},
{
"slot": 1,
"hero_id": 15,
"num_kills": 1,
"isRadiant": false
}
]
我想我需要尝试 model/schema 或 crud 函数之一,但真的不知道是哪一个? 另外,也许有一些无用或构建不佳的 pydantic 模式
PS : 我遵循了 FastAPI 文档的指南(我建议阅读)。
感谢您的帮助!
我相信你的问题不在fastapi的范围内,而是在sqlalchemy的范围内。 当您查询具有关系的 orm 对象时,fastapi 的标准是在访问它们时延迟加载关系。由于您从不直接访问关系 playerstats,因此它不会加载。参见 the docs 获取信息。
您的问题的解决方案应该是将 crud 函数更新为:
return db.query(models.Game).filter(models.Game.id == match_id)
.options(selectinload(models.Game.playerstats)).first()
"Select In Load" 是一种预加载类型,它将在提交查询时加载关系。如果您希望在每次查询时都出现这种行为,您可以将 orm 更新为:
playerstats = relationship("PlayerStat", back_populates="match", lazy="selectin")
希望对您有所帮助。这是我在 Whosebug 上的第一个答案 :)
编辑:实际上还有另一件事。在您的 orm 中,这种关系称为“playerstats”,而您在 pydantic 模型中将属性命名为“players”。那是行不通的。将 pydantic 属性名称从“players”更改为“playerstats”,现在一切正常。
编辑 2:正如您所猜测的那样,目前还不能一切正常。我刚刚看到还缺少另一件事。在 pydantic 模型中,您可以设置 orm 选项。这在使用 sqlalchemy 时非常重要。我向您所有的 pydantic 模型推荐这个。 这必须在每个 pydantic 模型及其属性模型上设置
class OtherModel(BaseModel):
value: str = None
class Config:
orm_mode = True
class SomePydanticModel(BaseModel):
value: str = None
some_other_model: OtherModel = None
class Config:
orm_mode = True
现在我们也可以再次修改你的crud方法的return语句:
return Game.from_orm(db.query(models.Game).options(selectinload(models.Game.playerstats)).filter(models.Game.id == match_id).first())
现在终于一切正常了:)