SQLAlchemy:如何仅在常量子句上与自定义primaryjoin建立关系

SQLAlchemy:如何仅在常量子句上与自定义primaryjoin建立关系,sqlalchemy,Sqlalchemy,我尝试改进泛型关联示例,以便在混合模型中不添加任何新列的情况下使用 当我尝试使用如下关系时: relationship(assoc_cls, primaryjoin=foreign(remote(assoc_cls.discriminator))==discriminator) 我面临一个错误: sqlalchemy.exc.ArgumentError:找不到任何简单等式 涉及主键的本地映射外键列的表达式 连接条件'address\u association.disc

我尝试改进泛型关联示例,以便在混合模型中不添加任何新列的情况下使用

当我尝试使用如下关系时:

relationship(assoc_cls,
             primaryjoin=foreign(remote(assoc_cls.discriminator))==discriminator)
我面临一个错误:

sqlalchemy.exc.ArgumentError:找不到任何简单等式 涉及主键的本地映射外键列的表达式 连接条件'address\u association.discriminator=:discriminator\u 1' 关于关系Supplier.address\u关联。确保引用 列与ForeignKey或ForeignKeyConstraint关联,或 在连接条件中使用foreign()注释对其进行注释。到 允许使用“==”以外的比较运算符,关系可以是 标记为viewonly=True

如何设置关系以获得如下所示的左连接

SELECT *
  FROM table_x 
       LEFT JOIN address_association ON address_association.discriminator='table_x'
是否可以设置关系以获取左侧外部联接

更新: 具有我尝试使用的属性的最后一个源代码版本

class BaseModelMixin(object):
    @db.declared_attr
    def fid(cls):
        return db.Column(db.Numeric(10,0), primary_key=True)

class Attr_type(BaseModelMixin, db.Model):
    __tablename__ = 'attributes'

    fsname = db.Column(db.Unicode(128), index=True, nullable=False)
    fitype = db.Column(db.Numeric(5,0), nullable=False, default=200)
    _fstable = db.Column('fstable', db.String(64), index=True, nullable=True)

class Attr_value(BaseModelMixin, db.Model):
    __tablename__ = 'table_attrs'

    firec_id = db.Column(db.Numeric(10,0), index=True, nullable=False)
    fiattr_id = db.Column(db.Numeric(10,0), db.ForeignKey('attributes.fid', ondelete='CASCADE'), index=True, nullable=False)
    attr_type = db.relation("Attr_type", lazy="joined", uselist=False)
    fitype = db.association_proxy("attr_type", "fitype")
    _fstable = db.association_proxy("attr_type", "_fstable")
    value = db.Column(db.Unicode(255))

    def __init__(self, value):
        self.value = value

class AttributesMixin(object):
    @property    
    def _table_attr_types(self):
        RowAttrVal = type("Attr_val_%s_%s" % (self.__tablename__, self.fid),
              (Attr_value, ),
              dict(
                   __mapper_args__ = {
                                      "polymorphic_on": "firec_id",
                                      "polymorphic_identity": self.fid
                                      }
                  )
              )

        TableAttrType = type("Attr_type_%s_%s" % (self.__tablename__, self.fid),
                         (Attr_type, ),
                         dict(
                              _values = db.relation(RowAttrVal,
                                                    uselist=False, 
                                                    ),
                              _value = db.association_proxy("_values", "value",
                              __mapper_args__ = {
                                                 "polymorphic_on": "_fstable",
                                                 "polymorphic_identity": self.__tablename__
                                                }
                              )
                         )

        return TableAttrType    

    def __new__(cls):        
        def get_attributes(self):
            return self._table_attr_types.query.all()

        def set_attributes(self, values):
            self._table_attr_types.query.set_by_jsons(values, decode=False)

        cls.attributes = property(get_attributes, set_attributes)

        return super(AttributesMixin, cls).__new__(cls)
更新2
-getter和setter属性可以工作,但是expression不确定这是否是您要寻找的模式,但这里是到目前为止的情况。为了代理到一个常规的@property,有很多方法可以做到这一点,在这里我重新调整了_associationstart的用途,但这只是任何具有代理行为的Python setlike对象

从sqlalchemy导入整数、外键、列、字符串、创建引擎
从sqlalchemy.orm导入关系、会话、exc作为orm_exc\
对象会话
从sqlalchemy.ext.declarative导入声明性基础
从sqlalchemy.ext.associationproxy导入\u AssociationSet
进口经营者
Base=声明性_Base()
类ThingAssociationSet(\u AssociationSet):
定义初始化(自,主机):
self.lazy\u collection=lambda:host.\u attributes.attributes
self.creator=lambda值:属性(值=值)
self.getter=operator.attrgetter(“值”)
def设定器(目标、值):
target.value=value
self.setter=setter
self.parent=None
类HasThings(对象):
事物类型=无
@财产
def_属性(自身):
sess=对象会话(自)
如果没有sess:
raise VALUERROR(“属性需要共享会话状态”)
尝试:
attrs=sess.query(AttributeCollection)\
筛选依据(type=self.thing\u type).one()
除orm_exc.NoResultFound外:
attrs=AttributeCollection(type=self.thing\u type)
附加(属性)
self._dict__['attributes']=attrs
返回属性
@财产
def属性(自身):
返回ThingAssociationSet(自身)
类属性集合(基):
__tablename\uuuu='attr\u collection'
id=列(整数,主键=True)
类型=列(字符串(30),可空=False)
属性=关系(“属性”,
collection\u class=set,cascade=“全部,删除孤立项”)
类属性(基):
__tablename_uu='attribute'
id=列(整数,主键=True)
collection\u id=列(ForeignKey('attr\u collection.id'))
value=Column(字符串(100),null=False)
X类(HasThings,Base):
事物类型='x'
__tablename_uux='x'
id=列(整数,主键=True)
Y类(HasThings,Base):
事物类型='y'
__tablename_uuu='y'
id=列(整数,主键=True)
e=创建引擎(“sqlite://”,echo=True)
Base.metadata.create_all(e)
sess=会话(e)
x1=X()
x2=X()
x3=X()
y1=Y()
y2=Y()
sess.add_all([x1,x2,x3,y1,y2])
x2.属性。添加(“x属性1”)
x3.属性。添加(“x属性2”)
y1.属性。添加(“y属性1”)
assert x3.attributes==set([“x属性1”,“x属性2”])
x1.属性。删除(“x属性1”)
断言x3.attributes==set([“x属性2”])

连接条件没有意义。它与表_x没有任何对应关系。我的意思是,在表_x行和所有地址_关联行之间具有某种过滤器的关系。您可以使用@属性,只加载地址_关联中的所有内容。它与表x没有外键或其他关系,因此它超出了
relationship()
的用途。“TableX”的每个实例都会得到完全相同的集合。当我使用该属性时,我需要在运行时创建一个具有多态关联的新类型(在我看来,这并不漂亮),但另一个问题是,在第一个请求后,值不会正确返回。但是,第一个请求返回了正确的值。我与这个问题斗争了一个月,我无法在_association.py上正确而简单地解决像discriminator_这样的Mixin问题,但必须在混合模型中添加列。谢谢你,Mike。这种式样很好。但是,我已经根据自己的需要对其进行了更改,并且遇到了同样的问题,即如果没有类变异,我无法向记录(模型实例)添加属性值。我所做的最后一件事是将属性getter和setter与显式查询连接和字段赋值一起使用——这是可行的,但您可能会看到其他更好的方法。