假设我们有这些类:
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
with a name
anddescription
属性,所以我会做这样的事情:
item = session.query(Item).first()
print item.data, item.name
所以这就是我想去的地方:将所有这些属性Item18N
直接从Item
. 当然,我必须在任何地方指定语言。但是,我找不到任何食谱,因为我什至不知道要搜索什么。SQLAlchemy 可以做这样的事情吗?
我还为我描述的所有内容创建了一个完整的示例(当然除了我不知道如何实现的部分)。
编辑:我已经玩了更多,看看我是否能想出一个更好的解决方案,到目前为止,我找到了一种可行的方法。我最初试图用它来实现它,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 数据然后将结果调整回一个的开销因此使得我一开始就全部提取完全无关紧要(因为语言环境将保持不变整个时间)。我的新完整示例显示了如何只执行一个查询并提供我的透明访问 - 但我想避免一个丑陋的开销。
该示例还包含一些我所做的转换。这可能指向该方向的解决方案,但我对此也不满意,因为它要求我with_transformation
每次都通过该部分。Item
如果在查询时会自动应用它,我会更好。但我没有发现任何事件或其他事件。
所以现在我有多种解决方案尝试,与上述业务逻辑相比,它们都缺乏直接访问的便利性。我希望有人能够弄清楚如何缩小这些差距以生产出漂亮干净的东西。