假设我们有这些类:
class Item(Base):
id = Column(Integer, primary_key=True)
data = Column(String)
i18ns = relationship("ItemI18n", backref="item")
class ItemI18n(Base):
lang_short = Column(String, primary_key=True)
item_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
name = Column(String)
这里的想法是将这个项目的名称用多种语言,例如英语和德语。到目前为止这个工作正常,人们可以很容易地使用它。但是,大多数情况下,我对所有(即两个)名称都不感兴趣,只对用户区域设置感兴趣。
例如,如果用户是英语并且想要用他的语言命名,我会看到两个选项:
# Use it as a list
item = session.query(Item).first()
print item.data, [i18n.name for i18n in item.i18ns if i18n.lang_short == "en"][0]
# Get the name separately
item, name = session.query(Item, ItemI18N.name).join(ItemI18N).filter(ItemI18N.lang_short == "en").first()
print item.data, name
第一个过滤列表,第二个分别查询语言。第二种是更有效的方式,因为它只提取真正需要的数据。但是,有一个缺点:我现在必须携带两个变量:item
和name
。例如,如果我要扩展我的ItemI18N
,请添加description
属性,然后我会查询ItemI18N
并随身携带。
但是业务逻辑是不同的:我希望Item
具有name
和description
属性,所以我会做这样的事情:
item = session.query(Item).first()
print item.data, item.name
这就是我要去的地方:将所有这些属性从Item18N
直接拉到Item
。当然,我必须在任何地方指定语言。但是,我找不到任何食谱,因为我甚至不知道要搜索什么。 SQLAlchemy能做这样的事吗?
我还为我描述的所有内容创建了complete example(当然除了我不知道如何实现的部分)。
编辑:我已经玩了很多,看看我能否提出更好的解决方案,到目前为止,我找到了一种方法。我最初试图用Query.get
来实现它,但这不能超越我的简单例子,因为现实是不同的。要解释一下,我必须通过添加Language
表来扩展我的初始模型,并将ItemI18N
转换为主键为(lang_id, item_id)
的多对多关系:
class ItemI18N(Base):
lang_id = Column(Integer, ForeignKey('language.id'), primary_key=True)
item_id = Column(Integer, ForeignKey('item.id'), primary_key=True)
name = Column(String)
language = relationship("Language", lazy="joined")
class Language(Base):
id = Column(Integer, primary_key=True)
short = Column(String)
现在,为了获得正确的语言环境,我只需将lazy="joined"
应用于完整路径,即可将所有加载项转换为连接加载项。这将不可避免地拉动所有语言,从而返回比我需要的更多的数据。我的方法完全独立于SQLAlchemy:
class Item(Base):
...
i18ns = relationship("ItemI18N", backref="item", cascade="all, delete-orphan", lazy="joined")
def name(self, locale):
for i18n in self.i18ns:
if i18n.language.short == locale:
return i18n.name
但这不是一个漂亮的解决方案,因为从数据库中检索所有 I18N数据,然后将结果装回 one ,从而完全解决了这个问题无关紧要的是我把所有东西都放在首位(因为语言环境将始终保持不变)。我的new full example显示了如何只执行一个查询并提供透明访问 - 但是我想避免使用丑陋的开销。
该示例还包含了一些我已经完成的transformations游戏。这可以指向这个方向的解决方案,但我对此并不满意,因为它要求我每次都要通过with_transformation
部分。如果在查询Item
时自动应用,我会更喜欢它。但我没有发现任何事件或其他事件。
所以现在我有多个解决方案尝试,与上述业务逻辑相比,都缺乏直接访问的便利性。我希望有人能够弄清楚如何缩小这些差距,以产生美观和干净的东西。