2017-01-16 77 views
0

我们正在将代码库转换为SqlAlchemy,其中有一个现有数据库,我们可以修改但不能完全替换。SQLAlchemy:将信息传递给自动映射多对多关系

有小部件的集合,并为每个插件,我们追踪的20个最相似的其他部件的(这是一个方向性的关系,即widget_2可以出现在widget_1最相似的窗口小部件,而不是相反)。

  • 有一个widget表具有widget_id领域和其他一些东西。

  • 有一个​​表有first_widget_id,second_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:%[email protected]%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其中second_widget_id == 1,其中对象EAS我们要first_widget_id == 1

+0

您能否对您的模型更具体一点?虽然您自动映射,但可能会创建一个[最小,完整且可验证的示例](http://stackoverflow.com/help/mcve),它反映了您遇到的问题。听起来你可能正在寻找[foreign_keys](http://docs.sqlalchemy.org/en/latest/orm/join_conditions.html)参数来处理多个连接路径,但我无法确定。 –

+0

更新了所有相关的代码。希望现在更清楚。 – user2449397

回答

1

您可以覆盖similarity_collection如何连接,甚至自动映射,与explicit class definition并通过foreign_keys的关系时:

base = automap_base() 

engine = create_engine(
    'mysql://%s:%[email protected]%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) 

如果你想也控制在创建关系(S)​​- 对于整洁的关联代理或类似 - 使用相同的模式。

+0

太棒了!我没有意识到可以像那样手动帮助自动映射。非常感谢! – user2449397