[英]SQLAlchemy - Using 'aliased' in query with custom primaryjoin relationship
我在Flask应用程序中使用SQLAlchemy(0.9.4)。 应用程序中有两个具有软删除支持的表。
class A(SoftDeleteMixin, db.Model):
id = db.Column(db.BigInteger, primary_key=True)
b_id = db.Column(db.BigInteger, db.ForeignKey('b.id'), nullable=False)
b = soft_delete_relationship('B.id', 'A.b_id')
class B(SoftDeleteMixin, db.Model):
id = db.Column(db.BigInteger, primary_key=True)
parent_id = db.Column(db.BigInteger, db.ForeignKey('b.id'))
parent = soft_delete_relationship(remote(id), parent_id, 'B.id', 'B.parent_id')
children = soft_delete_relationship(remote(parent_id), id, 'B.parent_id', 'B.id')
SoftDeleteMixin基于LimitingQuery( https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery )
from sqlalchemy.orm.query import Query
class NonDeletedQuery(Query):
def get(self, ident):
return Query.get(self.populate_existing(), ident)
def __iter__(self):
return Query.__iter__(self.private())
def from_self(self, *ent):
return Query.from_self(self.private(), *ent)
def private(self):
mzero = self._mapper_zero()
if mzero is not None and hasattr(mzero, 'class_'):
soft_deleted = getattr(mzero.class_, 'soft_deleted', None)
return self.enable_assertions(False).filter(soft_deleted.is_(False)) if soft_deleted else self
else:
return self
并且soft_delete_relationship用自定义的primaryjoin构造关系(用于非soft_deleted上的联接)。
def soft_delete_relationship(first, second, *args, **kwargs):
if isinstance(first, str) and isinstance(second, str):
other, other_column = first.split('.')
_this, this_column = second.split('.')
primaryjoin = ' & '.join(['({} == {})'.format(first, second), '{}.soft_deleted.is_(False)'.format(other)])
else:
other, other_column = args[0].split('.')
_this, this_column = args[1].split('.')
primaryjoin = lambda: (first == second) & getattr(second.table.c, 'soft_deleted').is_(False)
kwargs['primaryjoin'] = primaryjoin
return relationship(other, **kwargs)
当我使用别名B编写查询时,会发生问题:
b_parent = aliased(B)
A.query.join(A.b).outerjoin(b_parent, B.parent)
我得到以下SQL:
SELECT ... FROM a JOIN b ON b.id = a.b_id LEFT OUTER JOIN b AS b_1 ON b_1.id = b.parent_id AND *b*.soft_deleted IS False
但我期望以下几点:
SELECT ... FROM a JOIN b ON b.id = a.b_id LEFT OUTER JOIN b AS b_1 ON b_1.id = b.parent_id AND *b_1*.soft_deleted IS False
当我明确地写:
A.query.join(A.b).outerjoin(b_parent, (b_parent.id == B.parent_id) & b_parent.soft_deleted.is_(False))
我得到正确的查询。
在没有显式联接条件的情况下,如何在查询中为b_1获取适当的别名? 顺便说一句,SQLAlchemy 0.7.9中预期会有SQL。
好,我知道了。
getattr(second.table.c, 'soft_deleted')
也必须带有remote()注释。
换句话说primaryjoin
的relationship
在B.parent
应该是这样的:
(远程(B.id)== B.parent_id)和远程(B.soft_deleted).is_(假)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.