SQLAlchemy:将信息传递给自动化多对多关系

时间:2017-01-16 13:01:04

标签: python sqlalchemy flask-sqlalchemy

我们正在将代码库转换为SqlAlchemy,其中存在一个我们可以修改但不能完全替换的现有数据库。

有一组小部件,每个小部件我们跟踪20个最相似的小部件(这是一个方向性关系,即widget_2可以出现在widget_1最相似的小部件中,但反之亦然。)

  • 有一个widget表,其中包含widget_id字段和其他一些内容。

  • 有一个similarity表,其中包含first_widget_idsecond_widget_idsimilarity_score。我们只在数据库中保存了20个最相似的小部件,因此每个widget_id只显示first_widget_id的20倍。

  • first_widget_idsecond_widget_id的外键指向widget表。

我们正在使用SQLAlchemy的自动化功能,因此Widget对象具有Widget.similarity_collection字段。但是,对于指定的widget_id,它只包含second_widget_id == widget_id的项目,而我们需要first_widget_id == widget_id。据我所知,SQLAlchemy无法知道它应该选择哪一个。

我们能以某种方式告诉它吗?

编辑:根据评论,以下是模型的更多细节:

CREATE TABLE IF NOT EXISTS `similarity` (
  `first_widget_id` int(6) NOT NULL,
  `second_widget_id` int(6) NOT NULL,
  `score` int(5) NOT NULL,
  PRIMARY KEY (`first_widget_id`,`second_widget_id`),
  KEY `first_widget_id` (`first_widget_id`),
  KEY `second_widget_id_index` (`second_widget_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `similarity`
  ADD CONSTRAINT `similar_first_widget_id_to_widgets_foreign_key` FOREIGN KEY (`first_widget_id`) REFERENCES `widgets` (`widget_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `similar_second_widget_id_to_widgets_foreign_key` FOREIGN KEY (`second_widget_id`) REFERENCES `widgets` (`widget_id`) ON DELETE CASCADE ON UPDATE CASCADE;

CREATE TABLE IF NOT EXISTS `widgets` (
  `widget_id` int(6) NOT NULL AUTO_INCREMENT,
  `widget_name` varchar(70) NOT NULL,
  PRIMARY KEY (`game_id`),
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=13179 ;

使用此python代码初始化SQLAlchemy:

base = automap_base()

engine = create_engine(
    'mysql://%s:%s@%s/%s?charset=utf8mb4' % (
        config.DB_USER, config.DB_PASSWD, config.DB_HOST, config.DB_NAME
    ), echo=False
)

# reflect the tables
base.prepare(self.engine, reflect=True)

Widgets = base.classes.widgets

现在当我们做类似的事情时:

session.query(Widgets).filter_by(widget_id=1).similarity_collection

我们获得了sqlalchemy.ext.automap.similar的{​​{1}}个对象,而我们想要second_widget_id == 1

1 个答案:

答案 0 :(得分:1)

您可以覆盖similarity_collection加入explicit class definition并将foreign_keys传递给关系的方式,即使在自动加入时也是如此:

base = automap_base()

engine = create_engine(
    'mysql://%s:%s@%s/%s?charset=utf8mb4' % (
        config.DB_USER, config.DB_PASSWD, config.DB_HOST, config.DB_NAME
    ), echo=False
)

# The class definition that ensures certain join path for the relationship.
# Rest of the mapping is automapped upon reflecting.
class Widgets(base):
    __tablename__ = 'widgets'

    similarity_collection = relationship(
        'similarity', foreign_keys='similarity.first_widget_id')

base.prepare(self.engine, reflect=True)

如果您还希望控制similarity中创建的关系 - 对于整洁的关联代理等 - 使用相同的模式。