我正在尝试定义两个关系是间接关系的表之间的关系(即通过另外两个表)。
我正在寻找的结果可以使用此查询获取:
(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对象。
我正在努力弄清楚如何定义这种关系,类似于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: Could not locate any simple equality expressions involving locally mapped foreign key columns for primary join condition 'accounts.user_id = customers.id AND accounts.account_id = subscriptions.account_id AND pstn_numbers.sub_id = subscriptions.id' on relationship Customer.telnums. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation. To allow comparison operators other than '==', the relationship can be marked as viewonly=True.
有人能向我暗示正确的方向吗?
我有以下表结构(简化,除了每个表的一个之外,所有不相关的列都被删除):
class Customer(db.Model):
__tablename__ = 'customers'
id = db.Column(db.Integer, primary_key=True)
identification_num = db.Column(db.String(10), unique=True)
name = db.Column(db.Text)
invoices = db.relationship('Invoice', backref='customer')
accounts = db.relationship('Account', backref='customer')
def __init__(self):
pass
def __repr__(self):
return '<Customer %r>' % (self.name)
class Invoice(db.Model):
__tablename__ = 'invoices'
id = db.Column(db.Integer, primary_key=True)
customer_id = db.Column(db.Integer, db.ForeignKey('customers.id'))
active = db.Column(db.Boolean)
accounts = db.relationship('Account', backref='invoice')
def __repr__(self):
return '<Invoice %r>' % (self.id)
class Account(db.Model):
__tablename__ = 'accounts'
id = db.Column(db.Integer, primary_key=True)
account_id = db.Column(db.Integer, unique=True)
invoice_id = db.Column(db.Integer, db.ForeignKey('invoices.id'))
user_id = db.Column(db.Integer, db.ForeignKey('customers.id'))
active = db.Column(db.Boolean)
subscriptions = db.relationship('Subscription', backref='account')
def __repr__(self):
return '<Account %r>' % (self.account_id)
class Subscription(db.Model):
__tablename__ = 'subscriptions'
id = db.Column(db.Integer, primary_key=True)
account_id = db.Column(db.Integer, db.ForeignKey('accounts.account_id'))
sub_active = db.Column(db.DateTime)
telnums = db.relationship('Telnum', backref='subscription')
def __repr__(self):
return '<Subscription %r>' % (self.id)
class Telnum(db.Model):
__tablename__ = 'pstn_numbers'
id = db.Column(db.Integer, primary_key=True)
sub_id = db.Column(db.Integer, db.ForeignKey('subscriptions.id'))
telnum = db.Column(db.String(64))
holder = db.Column(db.String(10))
def __repr__(self):
return '<Telnum %r>' % (self.telnum)
答案 0 :(得分:10)
一般情况下,我不会将间接关系定义为relationship
,因为当您制作时,这些间接关系会变得不同步修改。您可以通过为relationship
指定viewonly=False
参数来解决其中一些限制。
更简单,风险更小,更直接的解决方案是使用查询(或启用查询的属性),以防您想从数据库重新加载数据,并使用python list comprehensions来获取子关系树的子孩子:
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
)