我正在使用 sqlalchemy 对以下关系进行建模:
- 有停靠点,并且许多停靠点可以具有相同的名称。
- 有翻译,多个翻译使用相同的站点名称(但不同的语言)。这样一站式名称就可以翻译成多种语言。
由于 stop_name 在停靠点中不是唯一的,当我尝试创建一对多关系时,sqlaclhemy+postgres 不喜欢它(见下文)。但这并不完全是一对多的。当我访问 stop.translations 时,我想要的是获取与此查询匹配的所有翻译:SELECT * from translation WHERE translation.stop_name == stop.stop_name
. 所以我在这里接受实际的多对多关系,但想对我的用户隐藏它,让它看起来像一对多。
我想过使用混合属性,但它们似乎只是标量,所以这不是一个真正的选择。我可能在尝试预先填充多对多关系时做得不好,因为这需要永远和超时。
一些上下文:这是 的一部分pygtfs
,但这是出错时的最小示例。当我运行以下脚本时:
import sqlalchemy
import sqlalchemy.orm
from sqlalchemy import Column
from sqlalchemy.types import Unicode
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Stop(Base):
__tablename__ = 'stop'
stop_id = Column(Unicode, primary_key=True)
stop_name = Column(Unicode)
# What I'd like:
translations = sqlalchemy.orm.relationship('Translation', viewonly=True,
primaryjoin="stop.c.stop_name==translation.c.stop_name")
class Translation(Base):
__tablename__ = 'translation'
stop_name = Column(Unicode, primary_key=True)
lang = Column(Unicode, primary_key=True)
translation = Column(Unicode)
if __name__ == "__main__":
engine = sqlalchemy.create_engine("postgresql://postgres@localhost:5432")
Session = sqlalchemy.orm.sessionmaker(bind=engine)
session = Session()
session.add(Stop(stop_id="hrld", stop_name="Herald Square"))
我得到:
[...]
sqlalchemy.exc.ArgumentError: Could not locate any relevant foreign key columns for primary join condition 'stop.stop_name = translation.stop_name' on relationship Stop.translations. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation.
我该怎么做才能在 sqlaclhemy 中映射它?
[评论后编辑]:如果我添加一个 ForeignKey,它会失败,因为 stop_name 不是唯一的(我不希望它是唯一的!):
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) there is no unique constraint matching given keys for referenced table "translation"
[SQL: '\nCREATE TABLE stop (\n\tstop_id VARCHAR NOT NULL, \n\tstop_name VARCHAR, \n\tPRIMARY KEY (stop_id), \n\tFOREIGN KEY(stop_name) REFERENCES translation (stop_name)\n)\n\n'] (Background on this error at: http://sqlalche.me/e/f405)