Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在具有多级/多重联接的SQLAlchemy中指定表关系?_Python_Sqlalchemy_Flask_Flask Sqlalchemy - Fatal编程技术网

Python 如何在具有多级/多重联接的SQLAlchemy中指定表关系?

Python 如何在具有多级/多重联接的SQLAlchemy中指定表关系?,python,sqlalchemy,flask,flask-sqlalchemy,Python,Sqlalchemy,Flask,Flask Sqlalchemy,我试图定义两个表之间的关系,这两个表的关系是间接的(即通过另外两个表) 我要查找的结果可以通过以下查询获取: (db.session.query(Telnum) .filter(Account.customer==customer) .filter(Account.account_id == Subscription.account_id) .filter(Telnum.sub_id == Subscription.id)

我试图定义两个表之间的关系,这两个表的关系是间接的(即通过另外两个表)

我要查找的结果可以通过以下查询获取:

(db.session.query(Telnum)
           .filter(Account.customer==customer)
           .filter(Account.account_id == Subscription.account_id)
           .filter(Telnum.sub_id == Subscription.id)
           .order_by(Telnum.telnum)
           .all()
)
其中,
customer
是客户对象

我正在努力弄清楚这将如何定义为一种关系,类似于
Customer.invoices
关系。我的想法是这样的:

telnums = db.relationship('Telnum',
                       primaryjoin="and_(Account.user_id==Customer.id, "
                       "Account.account_id == Subscription.account_id, " 
                       "Telnum.sub_id == Subscription.id)", 
                       backref='customer')
正如这篇文章所表明的,这是行不通的。它产生的错误消息如下:
sqlalchemy.exc.ArgumentError:在关系Customer.telnums上找不到任何涉及主联接条件“accounts.user\u id=customers.id和accounts.account\u id=subscriptions.id”的本地映射外键列的简单等式表达式。确保引用列与ForeignKey或ForeignKeyConstraint关联,或者在连接条件中使用foreign()注释进行注释。要允许使用“==”以外的比较运算符,可以将关系标记为viewonly=True。

谁能给我指一下正确的方向吗

我有以下表格结构(简化,删除了所有不相关的列,每个表格各有一列):

类别客户(数据库模型):
__tablename_uuu='客户'
id=db.Column(db.Integer,主键=True)
标识\u num=db.Column(db.String(10),unique=True)
name=db.Column(db.Text)
发票=数据库关系('Invoice',backref='customer')
accounts=db.relationship('Account',backref='customer')
定义初始化(自):
通过
定义报告(自我):
返回“”%(self.name)
类别发票(数据库模型):
__tablename_uuu=‘发票’
id=db.Column(db.Integer,主键=True)
customer\u id=db.Column(db.Integer,db.ForeignKey('customers.id'))
active=db.Column(db.Boolean)
accounts=db.relationship('Account',backref='invoice')
定义报告(自我):
返回“”%(self.id)
类别帐户(数据库模型):
__tablename_uuu='accounts'
id=db.Column(db.Integer,主键=True)
帐户id=db.Column(db.Integer,unique=True)
发票id=db.Column(db.Integer,db.ForeignKey('invoices.id'))
user_id=db.Column(db.Integer,db.ForeignKey('customers.id'))
active=db.Column(db.Boolean)
订阅=数据库关系('Subscription',backref='account')
定义报告(自我):
返回“”%(自我帐户\u id)
类订阅(db.Model):
__tablename_uu='订阅'
id=db.Column(db.Integer,主键=True)
account\u id=db.Column(db.Integer,db.ForeignKey('accounts.account\u id'))
sub_active=db.Column(db.DateTime)
telnums=db.relationship('Telnum',backref='subscription')
定义报告(自我):
返回“”%(self.id)
类Telnum(db.Model):
__tablename_uuu='pstn_u编号'
id=db.Column(db.Integer,主键=True)
sub_id=db.Column(db.Integer,db.ForeignKey('subscriptions.id'))
telnum=db.Column(db.String(64))
holder=db.Column(db.String(10))
定义报告(自我):
返回“”%(self.telnum)

一般来说,我不会将间接关系定义为
关系
,因为在进行修改时,这些间接关系可能会变得不同步。通过为
关系指定参数
,您可以绕过这些限制

一个更简单、风险更小、更直接的解决方案是,如果您希望从数据库重新加载数据,可以使用查询(或启用查询的属性),并使用python列表理解来获取关系树的子级:

class Customer(Base):
    # ...

    @property
    def telnums_qry(self):
        sess = Session.object_session(self)
        return (sess.query(Telnum)
                .join(Subscription)
                .join(Account)
                .filter(Account.user_id == self.id)
                ).all()


    @property
    def telnums_mem(self):
        return [tel
                for acc in self.accounts
                for sub in acc.subscriptions
                for tel in sub.telnums
                ]


class Telnum(Base):
    # ...

    @property
    def customer(self):
        return (self.subscription
                and self.subscription.account
                and self.subscription.account.customer
                )

问题1:您是否试图从
客户那里获得
电话号码?问题2:你真的需要一个关系,还是一个查询(或启用查询的属性)就足够了?@van A1:是的,我正在尝试获取属于某个客户的所有Telnums。客户可以有许多帐户,这些帐户可以有许多订阅,然后可以有许多telnum。我想我并不真的需要这种关系。我曾考虑在Customer中创建一个函数来执行查询并返回数据,但我认为建立关系可能是“正确”且干净的方法。我也在尝试更好地掌握SQLAlchemy。非常感谢!最后使用telnums_qry来支持telnums_mem,因为它会更快一点。还感谢您通过使用联接来清理查询——了解了如何使用预先存在/预定义的关系使查询更加简洁。太好了。不过,使用query每次都会发出一个查询,而使用
会话(UnitOfWork)
只会加载一次对象,那么纯python应该更快,因为不涉及IO(db调用)。基本上,这取决于用例。您还可以配置关系,以便在您的用例无论如何都需要它们的情况下急切地加载它们。很高兴知道。这个特定的用例很可能只使用一次数据,但我很感激为未来潜在的用例提供的信息。我没有足够高的声誉来支持你的答案。抱歉:(@van我有点困惑。你说使用会话只会加载一次对象,每次查询都会命中数据库。但是,你的查询有会话,而列表理解没有。如果只使用列表理解,它什么时候(如果有的话)会第二次查询数据库?还有,“@property”有什么意义除了必须添加()来调用类方法之外?@Chockomonkey:您的一些问题的答案是“视情况而定”。
telnums\u qry
将执行一个查询,该查询将获取所有子子项,因此只会对数据库执行一次(并且每次访问属性时都会再次执行).
telnums\u mem
将基本上“按需”导航子级、子级和子级子级。如果这些都已加载
class Customer(Base):
    # ...

    @property
    def telnums_qry(self):
        sess = Session.object_session(self)
        return (sess.query(Telnum)
                .join(Subscription)
                .join(Account)
                .filter(Account.user_id == self.id)
                ).all()


    @property
    def telnums_mem(self):
        return [tel
                for acc in self.accounts
                for sub in acc.subscriptions
                for tel in sub.telnums
                ]


class Telnum(Base):
    # ...

    @property
    def customer(self):
        return (self.subscription
                and self.subscription.account
                and self.subscription.account.customer
                )