Flask SQLAlchemy从查询结果中的两个联接的映射实体获取列

时间:2018-10-30 14:09:12

标签: python sqlalchemy flask-sqlalchemy

我有一张表格Fatal error: Uncaught Error: Class 'Google_Client' not found in /Users/xxxx/app.php:8 Stack trace: #0 {main} thrown in /Users/xxxx/app.php on line 8 ,它代表在我的应用程序的下拉列表中找到的所有选项。每个选项都可以通过其所属菜单(例如MenuOptions)和该选项的特定值(MenuOptions.menu_name)来识别。

此表在我的数据库中具有所有关系,并且不使用外键,因此我很难使其与SQLAlchemy啮合。

在SQL中,它很简单:

MenuOptions.option_value

定义此关系。但是,在SQLAlchemy中这样做时会遇到麻烦,因为如果没有外键,我将无法清晰地映射这种关系。在SQLAlchemy中,到目前为止我做得最好的是:

SELECT 
    *
FROM
    document
        JOIN
    menu_options ON menu_options.option_menu_name = 'document_type'
        AND menu_options.option_value = document.document_type_id

这确实起作用,并且确实返回正确的值,但是将它们作为两个单独的模型对象的列表返回,因此我必须通过the_doc = db.session.query(Document, MenuOptions).filter( Document.id == document_id ).join( MenuOptions, and_( MenuOptions.menu_name == text('"document_type"'), MenuOptions.value == Document.type_id ) ).first() 引用映射的Document属性,并通过{{1 }}

有没有一种方法可以让我获得不带外键或模型中任何the_doc[0] 的所有属性作为单个查询对象的返回关系?我已经尝试过the_doc[1]ForeignKeyConstraint,但得到的结果基本相同。

2 个答案:

答案 0 :(得分:1)

您可以使用with_entities

entities = [getattr(Document, c) for c in Document.__table__.columns.keys()] + \
           [getattr(MenuOptions, c) for c in MenuOptions.__table__.columns.keys()]

session.query(Document, MenuOptions).filter(
    Document.id == document_id
).join(
    MenuOptions,
    and_(
        MenuOptions.menu_name == text('"document_type"'),
        MenuOptions.value == Document.type_id
    )
).with_entities(*entities)

答案 1 :(得分:0)

我最终使用association_proxy采取了一种略有不同的方法,但是如果您最终从google那里来到这里,那么这应该会对您有所帮助。在以下示例中,我将document_type_id存储在document表中,并将该ID的对应值保存在名为menu_options的表中。通常,您会为此使用外键,但是我们的menu_options本质上是一个内部查找表,它包含与其他几张表的关系,因此外键不是一个干净的解决方案。

首先通过primaryjoin属性建立关系,然后使用associationproxy,我可以使用以下代码立即基于document_type加载document_type_id

from sqlalchemy import and_
from sqlalchemy.ext.associationproxy import association_proxy

class Document(db.Model):
    __tablename__ = "document"
    document_type_id = db.Column(db.Integer)
    document_type_proxy = db.relationship(
        "MenuOptions",
        primaryjoin=(
            and_(
                MenuOptions.menu_name=='document_type', 
                foreign('Document.document_type_id')==MenuOptions.value
            )
        ),
        lazy="immediate"
        viewonly=True
    )

如果只需要一个映射关系,而无需在数据库中使用外键,那么就可以了。但是,如果您希望能够直接将远程属性(在这种情况下为document_type)作为初始类(在这种情况下为Document)上的属性来访问,则可以使用{{1 }}为此,只需传递映射关系的名称和远程属性的名称:

association_proxy