SQLAlchemy ORM 关系停止工作

SQLAlchemy ORM Relationship stopped working

我使用 FastAPI、sqlalchemy 和 pydantic 构建了一个 API。 ORM 建模在一段时间内运行良好,但我更新了代码并以某种方式破坏了关系映射。请帮助我弄清楚我在 ORM 映射中做错了什么。

当我访问 http://localhost:8000/test-rel 时,我希望看到这个:

[{"name":"P One","pk_id":1,"fk_id":1, "test":{"test_id":1, "test_name":"One"}},{"name":"P Two","pk_id":2,"fk_id":2, "test":{"test_id":2, "test_name":"Two"}},{"name":"P Three","pk_id":3,"fk_id":null, "test": null}]

但我看到的是:

[{"name":"P One","pk_id":1,"fk_id":1},{"name":"P Two","pk_id":2,"fk_id":2},{"name":"P Three","pk_id":3,"fk_id":null}]

这是我用来排除故障的项目的测试代码部分:

schemas.py

from typing import Optional

from pydantic import BaseModel

class Test(BaseModel):
    test_id: int
    test_name: str


class TestP(BaseModel):
    pk_id: int
    fk_id: Optional[int]
    name: Optional[str]

    test: Test

    class Config:
        orm_mode = True

models.py

from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, DATE, DECIMAL
from sqlalchemy.orm import relationship

from sql_app.database import Base

class Test(Base):
    __tablename__ = "test"

    test_id = Column(Integer, primary_key=True)
    test_name = Column(String)


class TestP(Base):
    __tablename__ = "test_p"

    pk_id = Column(Integer, primary_key=True)
    fk_id = Column(Integer, ForeignKey("test.test_id"), nullable=True)
    name = Column(String, nullable=True)

    test = relationship("Test")

database.py

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import urllib

params = urllib.parse.quote_plus("DRIVER={SQL Server Native Client 11.0};"
                                 "SERVER=SQLEXPRESS;"
                                 "DATABASE=Test;"
                                 "Trusted_Connection=yes")

engine = create_engine(
    "mssql+pyodbc:///?odbc_connect={}".format(params)
)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

crud.py

from sqlalchemy.orm import Session
from sqlalchemy import and_, update, delete
from fastapi.encoders import jsonable_encoder
from typing import List

from sql_app import models
from sql_app import schemas

def test_rel(db: Session) -> List[schemas.TestP]:
    return db.query(models.TestP).all()

main.py

import babel.numbers as bn
from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session

from sql_app import crud, models, schemas
from sql_app.database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI()

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

@app.get("/test-rel/")
def test_rel(db: Session = Depends(get_db)):
    return crud.test_rel(db=db)

在 CaseIIT 的 github 讨论中回答:

几件事:

def test_rel(db: Session) -> List[schemas.TestP]:
    return db.query(models.TestP).all()
This returns a List[model.TestP]

默认情况下,关系也是延迟加载的。查看 https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html 以获得预加载选项

我的回复: 这正是我要找的。我不知道默认情况下关系是延迟加载的。我的代码使用 pydantic 来验证响应,而我的查询验证失败,因为 pydantic 验证没有看到连接的表。我更新了我的代码以添加预先加载,它现在完全按照我的预期工作。

test = relationship("Test", lazy='joined')