【问题标题】:Sqlalchemy include empty relationship with join and contains_eagerSqlalchemy 包含与 join 和 contains_eager 的空关系
【发布时间】:2019-11-12 23:59:27
【问题描述】:

我有 2 个模型 Recording 和 Recording_results 像这样

class Recording(Base):
    __tablename__ = 'recordings'

    id = Column(Integer, primary_key=True)
    filename = Column(String, nullable=False)

    language_id = Column(Integer, ForeignKey('languages.id'), nullable=False)
    language = relationship("Language", back_populates="recordings")

    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    user = relationship("User", back_populates="recordings")

    created_at = Column(DateTime, nullable=False, default=func.now())
    updated_at = Column(DateTime, nullable=False,
                        default=func.now(), onupdate=func.now())
    deletedd_at = Column(DateTime, nullable=True)

    def __repr__(self):
        return 'id: {}'.format(self.id)

User.recordings = relationship("Recording", order_by=Recording.id, back_populates="user")
Language.recordings = relationship("Recording", order_by=Recording.id, back_populates="language")


class RecordingResult(Base):
    __tablename__ = 'recording_results'

    id = Column(Integer, primary_key=True)
    is_with_dictionary = Column(Boolean, default=False)
    result = Column(String, nullable=True)
    run_time = Column(Float, default=0.0)

    recording_id = Column(Integer, ForeignKey('recordings.id'), nullable=False)
    recording = relationship("Recording", back_populates="recording_results", lazy="joined")

    speech_service_id = Column(Integer, ForeignKey('speech_services.id'), nullable=False)
    speech_service = relationship("SpeechService", back_populates="recording_results")

    created_at = Column(DateTime, nullable=False, default=func.now())
    updated_at = Column(DateTime, nullable=False,
                        default=func.now(), onupdate=func.now())
    deletedd_at = Column(DateTime, nullable=True)

    def __repr__(self):
        return 'id: {}'.format(self.id)

Recording.recording_results = relationship("RecordingResult", order_by="desc(RecordingResult.id)", back_populates="recording", lazy="joined")
SpeechService.recording_results = relationship("RecordingResult", order_by=RecordingResult.id, back_populates="speech_service")

我需要获取不包括recording_results的记录项目列表以及条件(Recording.user_id == id,Recording.deletedd==None,RecordingResult.deletedd==None)

我使用了这个查询

db.session.query(Recording).filter(Recording.user_id == id, Recording.deletedd_at == None).order_by(Recording.id.desc()).join(Recording.recording_results).options(contains_eager(Recording.recording_results)).filter(RecordingResult.deletedd_at == None).all()

它过滤掉但似乎加入方法不包括记录与空的recording_results关系

我使用棉花糖将结果打印到 json

我的结果:

{
        "id": 4,
        "filename": "15615378415768423_test.txt",
        "language_id": 1,
        "user_id": 2,
        "recording_results": [
            {
                "id": 5,
                "is_with_dictionary": true,
                "result": "test5",
                "run_time": 1200.2,
                "recording_id": 4,
                "speech_service_id": 2
            }
        ],
        "created_at": "2019-06-26T08:30:41.591410+00:00"
    },
    {
        "id": 2,
        "filename": "15615371606083994_test.txt",
        "language_id": 2,
        "user_id": 2,
        "recording_results": [
            {
                "id": 1,
                "is_with_dictionary": true,
                "result": "test1",
                "run_time": 1500.2,
                "recording_id": 2,
                "speech_service_id": 4
            },
            {
                "id": 2,
                "is_with_dictionary": false,
                "result": "test2",
                "run_time": 1600.2,
                "recording_id": 2,
                "speech_service_id": 3
            }
        ],
        "created_at": "2019-06-26T08:19:20.628205+00:00"
    }

预期结果:

{
        "id": 5,
        "filename": "15616009750201173_test.txt",
        "language_id": 1,
        "user_id": 2,
        "recording_results": [],
        "created_at": "2019-06-27T02:02:55.035810+00:00"
    },
    {
        "id": 4,
        "filename": "15615378415768423_test.txt",
        "language_id": 1,
        "user_id": 2,
        "recording_results": [
            {
                "id": 5,
                "is_with_dictionary": true,
                "result": "test5",
                "run_time": 1200.2,
                "recording_id": 4,
                "speech_service_id": 2
            }
        ],
        "created_at": "2019-06-26T08:30:41.591410+00:00"
    },
    {
        "id": 2,
        "filename": "15615371606083994_test.txt",
        "language_id": 2,
        "user_id": 2,
        "recording_results": [
            {
                "id": 2,
                "is_with_dictionary": false,
                "result": "test2",
                "run_time": 1600.2,
                "recording_id": 2,
                "speech_service_id": 3
            },
            {
                "id": 1,
                "is_with_dictionary": true,
                "result": "test1",
                "run_time": 1500.2,
                "recording_id": 2,
                "speech_service_id": 4
            }
        ],
        "created_at": "2019-06-26T08:19:20.628205+00:00"
    }

如何在连接查询中也包含空关系?

【问题讨论】:

    标签: python json filter sqlalchemy relationship


    【解决方案1】:

    一个INNER JOIN,就像由

    join(Recording.recording_results)
    

    只有在连接的两边都存在匹配行时才会生成一行。

    Query.outerjoin() 生成的LEFT [OUTER] JOIN 将包含左侧的行,而右侧没有匹配的行,因此如果您没有使用右表的其他谓词,则更改连接类型会有所帮助。

    事实上你是这样做的,但它有点像“工作”,因为它是一个IS NULL 检查。不过,在这种情况下,它的正确位置是 ON 子句:

    outerjoin(RecordingResult, and_(Recording.recording_results, RecordingResult.deletedd_at == None))
    

    它取代了filter()的使用。

    【讨论】:

    • 我得到了 sqlalchemy.exc.ArgumentError: Expected mapped entity or selectable/table as join target error,为什么它没有将记录结果重新设置为连接映射?
    • 嗯,稍后再看看发生了什么。
    • 是的,如果我将连接更改为外连接,则错误仅在使用 ON 子句的示例中显示,然后它才起作用
    • 已解决,当使用显式的ON 子句时,目标应该是错误所说的——在这种情况下是RecordingResult
    猜你喜欢
    • 2020-06-09
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 2023-04-02
    • 2021-11-14
    • 2011-09-22
    • 1970-01-01
    • 2021-03-13
    相关资源
    最近更新 更多