Generic Association with generic fk: 无法摆脱重叠警告

Generic Association with generic fk: Can't get rid of overlap warning

在我无法控制的数据库中,我认为 Generic Association 使用通用外键。简而言之:CommunicationInterface 属于 Router 或 Server,决不属于两者。没有鉴别器,因为 id 在整个数据库中是唯一的。

为简洁起见缩短了代码:

class Server(...):
    __tablename__ = 'server'

    id = Column('_oid', Integer, primary_key=True)

    interfaces = relationship(
        'CommunicationInterface', backref='server',
        primaryjoin='Server.id == foreign(CommunicationInterface.parent_id)'
    )


class Router(...):
    __tablename__ = 'router'

    id = Column('_oid', Integer, primary_key=True)
    interfaces = relationship(
        'CommunicationInterface', backref='router',
        primaryjoin='Router.id == foreign(CommunicationInterface.parent_id)'
    )


class CommunicationInterface(...):
    __tablename__ = 'communicationinterface'

    id = Column('_oid', Integer, primary_key=True)
    parent_id = Column('_parent_oid', Integer)
    
    overlaps = 'router,server'
    router = relationship(
        'Router', back_populates='interfaces', overlaps=overlaps,
        primaryjoin='Router.id == foreign(CommunicationInterface.parent_id)'
    )
    server = relationship(
        'Server', back_populates='interfaces', overlaps=overlaps,
        primaryjoin='Server.id == foreign(CommunicationInterface.parent_id)'
    )

即使使用重叠参数,这仍然会给我如下警告:

SAWarning: relationship 'Router.interfaces' will copy column router._oid to column communicationinterface._parent_oid, which conflicts with relationship(s): 'CommunicationInterface.server' (copies elb_server._oid to elb_communicationinterface._parent_oid). If this is not the intention, consider if these relationships should be linked with back_populates, or if viewonly=True should be applied to one or more if they are read-only. For the less common case that foreign key constraints are partially overlapping, the orm.foreign() annotation can be used to isolate the columns that should be written towards. The 'overlaps' parameter may be used to remove this warning.

有没有更好的方法来声明这些关系?如果不是,我是否使用了错误的 overlaps 参数?

您遇到的问题有以下几个原因:

  • backrefback_populates 的混合
    • backref 也在另一边创建一个 relationship
    • back_populates 期望另一边 relationship
  • overlaps 另一边 relationship 不正确

这应该可以解决您的问题:

class Server(Base):
    __tablename__ = 'server'

    id = Column('_oid', Integer, primary_key=True)

    
class Router(Base):
    __tablename__ = 'router'

    id = Column('_oid', Integer, primary_key=True)


class CommunicationInterface(Base):
    __tablename__ = 'communicationinterface'

    id = Column('_oid', Integer, primary_key=True)
    parent_id = Column('_parent_oid', Integer)
    
    router = relationship(
        'Router', backref=backref('interface', lazy='subquery', overlaps='server, interface'),
        primaryjoin='Router.id == foreign(CommunicationInterface.parent_id)'
    )
    server = relationship(
        'Server', backref=backref('interface', lazy='subquery', overlaps='router'), overlaps='router',
        primaryjoin='Server.id == foreign(CommunicationInterface.parent_id)'
    )

或者如果你想用 back_populates:

class Server(Base):
    __tablename__ = 'server'

    id = Column('_oid', Integer, primary_key=True)

    interface = relationship(
        'CommunicationInterface', back_populates='server', overlaps='router',
        primaryjoin='Server.id == foreign(CommunicationInterface.parent_id)'
    )

class Router(Base):
    __tablename__ = 'router'

    id = Column('_oid', Integer, primary_key=True)
    
    interface = relationship(
        'CommunicationInterface', back_populates='router', overlaps='server, interface',
        primaryjoin='Router.id == foreign(CommunicationInterface.parent_id)'
    )


class CommunicationInterface(Base):
    __tablename__ = 'communicationinterface'

    id = Column('_oid', Integer, primary_key=True)
    parent_id = Column('_parent_oid', Integer)
    
    router = relationship(
        'Router', back_populates='interface',
        primaryjoin='Router.id == foreign(CommunicationInterface.parent_id)'
    )
    server = relationship(
        'Server', back_populates='interface', overlaps='router',
        primaryjoin='Server.id == foreign(CommunicationInterface.parent_id)'
    )