简体   繁体   English

没有外键的SQLAlchemy经典关系

[英]SQLAlchemy Classical Relationship with No Foreign Key

I'm trying to relate two tables that have multiple 'secondary' tables. 我正在尝试关联具有多个“辅助”表的两个表。 Instead of the declarative syntax, it's necessary that I use the classical. 除了使用声明性语法外,我还必须使用经典语法。 Here is a simplified schema: 这是一个简化的模式:

class Apple:
  def __init__(self, id=None, name=None):
    # ...

class Recipe:
  def __init__(self, id=None, appleId=None, name=None):
    # ...

class Blog:
  def __init__(self, id=None, name=None, recipeId=None, bloggerId=None):
    # ...

class Blogger:
  def __init__(self, name)
    # ...

appleTable = Table('Apple', metadata, Column('id', Integer, primary_key=True), Column('name', String(256)))
recipeTable = Table('Recipe', metadata, Column('id', Integer, primary_key=True), Column('name', String(256)), Column('appleId', Integer, ForeignKey('Apple.id')))
blogTable = Table('Blog', metadata, Column('id', Integer, primary_key=True), Column('name', String(256)), Column('recipeId', Integer, ForeignKey('Recipe.id')), Column('bloggerId', Integer, ForeignKey('Blogger.id')) ) 
bloggerTable = Table('Blogger', metadata, Column('id', Integer, primary_key=True), Column('name', String(256)))


# call mapper on all tables/classes
# ... #

# Relate 'Apple' to 'Blogger' using 'Recipe' and 'Blog' as intermediates 
Apple.appleBloggers = relationship(Blogger, secondary=..., primaryjoin=..., secondaryjoin=...)

What relationship would I need to place into the appleBloggers attribute of Apple in order to retrieve all bloggers who've blogged about apple recipes? 我需要将什么关系放入AppleappleBloggers属性中,以便检索所有已经写过有关苹果食谱的博客作者?


Edit: Solution 编辑:解决方案

An alternative @univerio 's solution is posted below. @univerio的替代解决方案在下面发布。 The difference being with the usage of the mapped objects vs the table variables. 区别在于映射对象与表变量的用法。 I've also added a viewonly parameter, which prevents writes to the attribute. 我还添加了一个viewonly参数,该参数可以防止写入属性。

mapper(Apple, appleTable, properties = {
  "appleBloggers": relationship(Blogger,
            secondary=join(Recipe, Blog, Recipe.id == Blog.recipeId),
            secondaryjoin=lambda: and_(Apple.id == Recipe.appleId, Blogger.id == Blog.bloggerId),
            viewonly=True)
})

Original Attempt 原始尝试

Here is what I've tried: 这是我尝试过的:

Apple.appleBloggers = relationship(Blogger, 
    secondary=join(Recipe, Blog, Recipe.id==Blog.recipeId),
    primaryjoin= Apple.id == Recipe.appleId,
    secondaryjoin= Blog.bloggerId == Blogger.id)

But whenever I do the following: 但是,只要我执行以下操作:

apple = Apple(name="RedDelicious")
session.add(apple)
session.commit()
print(apple.appleBloggers)

I get the error: 我得到错误:

File ".../.pyenv/versions/2.7.10/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1425, in __str__
  return str(self.parent.class_.__name__) + "." + self.key
File ".../.pyenv/versions/2.7.10/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 840, in __getattr__
  return self._fallback_getattr(key)
File ".../.pyenv/versions/2.7.10/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 818, in _fallback_getattr
  raise AttributeError(key)
AttributeError: parent

You're mixing declarative and classical mappings. 您正在混合声明式映射和经典映射。 Assigning a relationship like that only works for declarative. 分配这样的relationship仅适用于声明式。 The proper way to do this in classical mapping is: 在经典映射中执行此操作的正确方法是:

mapper(Apple, appleTable, properties={
    "appleBloggers": relationship(Blogger,
                                  secondary=recipeTable.join(blogTable, recipeTable.c.id == blogTable.c.recipeId),
                                  primaryjoin=appleTable.c.id == recipeTable.c.appleId,
                                  secondaryjoin=blogTable.c.bloggerId == bloggerTable.c.id)
})

Alternative Solution (with mapped objects): 替代解决方案(带有映射对象):

mapper(Apple, appleTable, properties = {
  "appleBloggers": relationship(Blogger,
            secondary=join(Recipe, Blog, Recipe.id == Blog.recipeId),
            secondaryjoin=lambda: and_(Apple.id == Recipe.appleId, Blogger.id == Blog.bloggerId),
            viewonly=True)
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM