【问题标题】:sqlalchemy: troubles creating and getting one to many relationship, Why do I get InstrumentedList instead of Listsqlalchemy:创建和获取一对多关系时遇到问题,为什么我得到 InstrumentedList 而不是 List
【发布时间】:2021-08-11 00:19:38
【问题描述】:

我是使用 SqlAlchemy 的新手,现在我使用的是 fastAPI,基本上我需要创建一个可以有多个嵌套参数的指标模型

这是我的代码

class Indicator(Base):
    __tablename__ = "indicator"
    id = Column(Integer, primary_key=True, autoincrement=True, index=True)
    name = Column(String, unique=True, nullable=False)
    indicator_lib_name = Column(String, unique=True, nullable=False)
    properties = relationship("Property", backref="indicator", lazy=True,cascade="all, delete")

class Property(Base):
    __tablename__ = "property"
    id = Column(Integer, primary_key=True, autoincrement=True, index=True)
    name = Column(String, unique=True, nullable=False)
    value = Column(sqlalchemy_utils.ScalarListType, nullable=True)
    indicator_id = Column(Integer, ForeignKey("indicator.id", ondelete="CASCADE"))
    # indicator = relationship("Indicator", back_populates="properties")

from pydantic import BaseModel

class Property(BaseModel):
    id: Optional[int]
    name: str
    value: List[Any]

class IndicatorCreate(BaseModel):
    name: str
    indicator_lib_name: Optional[str]
    properties: List[Property]

# https://stackoverflow.com/questions/61144192/insert-a-nested-schema-into-a-database-with-fastapi
# https://dev.to/brandonwallace/one-to-many-relationships-complete-how-to-2nbi
def create_new_indicator(db: Session, indicator: IndicatorCreate):
    indicator_data = indicator.dict()
    properties = []
    if indicator.properties:
        properties = indicator_data.pop("properties", None)

    new_indicator = Indicator(**indicator_data)
    new_indicator.indicator_lib_name = indicator.indicator_lib_name or indicator.name

    db.add(new_indicator)
    db.commit()
    db.refresh(new_indicator)

    for prpty in properties:
        # prpty["indicator"] = new_indicator
        property_model = Property(**prpty, indicator=new_indicator)
        db.add(property_model)
        db.commit()
        db.refresh(property_model)

    db.refresh(new_indicator)
    return new_indicator
@indicators_router.post("/", response_model=IndicatorBase)
def create_indicator(indicator: IndicatorCreate, db: Session = Depends(get_db)):
    indicator_new = create_new_indicator(db, indicator)
    print("indicator ", indicator_new)
    return indicator_new
data = {
    "name": "adx",
    "indicator_name": "adx",
    "properties": [{"name": "range", "value": [2]}],
}

def test_create_indicator(client):
    global data
    response = client.post("/indicators/", json.dumps(data))
    data = response.json()
    print(data)
    assert response.status_code == 200
    assert data["name"] == "adx"
    assert data["id"] == 1
    assert len(data["properties"]) == 1

错误是

>               raise ValidationError(errors, field.type_)
E               pydantic.error_wrappers.ValidationError: 1 validation error for IndicatorBase
E               response -> properties -> 0
E                 value is not a valid dict (type=type_error.dict)

当我调试代码时,我可以看到属性填充正确,它得到的数据很好,但结构是 InstrumentedList 而不是 List,为什么?如何将其转换为列表或更好的问题:实现此目标的更好方法是什么?

我创建指标和参数的方式更好吗?还是有更简洁的方法?

非常感谢你们,希望你们能帮助我迈出 SQLAlchemy 的第一步

【问题讨论】:

  • 如果您想了解有关 InstrumentedList 的更多信息:stackoverflow.com/questions/6654613/…
  • 您的定义中没有包含IndicatorBase;但属性未定义为可从 ORM 加载(即使用 .foo 而不是 ['foo']。您可以通过在架构类中添加 class Config: orm_mode = True 来更改它;这就是为什么 pydantic 类需要一个 dict:fastapi.tiangolo.com/tutorial/sql-databases/…
  • @MatsLindh 成功了!谢谢,我为 IndicatorBase 添加了orm_mode = true,但没有为 Property 添加,这就是问题所在,您能否包含您的答案以便接受它为有效的?

标签: python sqlalchemy fastapi


【解决方案1】:

您的 Property 架构未定义为可从 ORM 加载(即在源对象中使用 .foo 而不是 ['foo'])。

您可以通过添加来更改此设置

class Config: 
    orm_mode = True 

在您的架构类中。因为这不存在,所以 pydantic 期望 dict-alike(即属性可以通过字典查找来解析)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-09
    • 2011-04-17
    • 2016-04-06
    • 2022-01-17
    • 2014-07-21
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    相关资源
    最近更新 更多