【问题标题】:sqlalchemy Error creating backref on relationshipsqlalchemy 在关系上创建反向引用时出错
【发布时间】:2014-12-28 20:35:17
【问题描述】:

我有两个非常简单的模型。在我的Post 模型中,User 表中应该有两个关系。一个用于帖子的所有者,一个用于帖子的最后一位编辑。它们可以是不同的值,但都引用同一个User 表。

我的模型是这样设置的

class Post(Base):
    last_editor_id = Column(BigInteger, ForeignKey('users.id'), nullable=True)
    last_editor = relationship('User', backref='posts', foreign_keys=[last_editor_id])
    owner_id = Column(BigInteger, ForeignKey('users.id'), nullable=False, index=True)
    owner = relationship('User', backref='posts', foreign_keys=[owner_id])

class User(Base):
    '''This represents a user on the site'''
    __tablename__ = 'users'
    id = Column(BigInteger, primary_key=True, unique=True)
    name = Column(BigInteger, nullable=False)

当我尝试创建这些模型时,我收到以下错误

sqlalchemy.exc.ArgumentError: Error creating backref 'posts' on relationship 'Post.owner': property of that name exists on mapper 'Mapper|User|users'

如何更正此问题,以便在 Post 模型中维护两个外键?

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    错误告诉您,您不止一次使用post 作为您的反向引用的名称,您需要做的就是提供反向引用的唯一名称。这是一个完整的例子——我在 Post 类中添加了一个 id 主键,还添加了一些 __repr__s,所以我们得到了一些可读的输出。

    from sqlalchemy import create_engine
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, BigInteger, ForeignKey, Integer
    from sqlalchemy.orm import relationship, sessionmaker
    
    Base = declarative_base()
    engine = create_engine('sqlite://') ## In Memory.
    Session = sessionmaker()
    Session.configure(bind=engine)
    session = Session()
    
    class Post(Base):
        __tablename__ = 'post'
        id = Column(Integer, primary_key=True)
        last_editor_id = Column(BigInteger, ForeignKey('users.id'), nullable=True)
        last_editor = relationship('User', backref='editor_posts', foreign_keys=[last_editor_id])
        owner_id = Column(BigInteger, ForeignKey('users.id'), nullable=False, index=True)
        owner = relationship('User', backref='owner_posts', foreign_keys=[owner_id])
    
        def __repr__(self):
            return '<Post: {}>'.format(self.id)
    
    
    class User(Base):
        '''This represents a user on the site'''
        __tablename__ = 'users'
        id = Column(BigInteger, primary_key=True, unique=True)
        name = Column(BigInteger, nullable=False)
    
        def __repr__(self):
            return '<User: {}>'.format(self.name)
    
    
    
    Base.metadata.create_all(engine)
    
    bob = User(name='Bob', id=1)
    alice = User(name='Alice', id=2)
    post = Post(owner=alice, last_editor=bob, id=1)
    
    session.add(post)
    session.commit()
    
    bob = session.query(User).get(1)
    print bob
    # <User: Bob>
    print bob.editor_posts
    # [<Post: 1>]
    print bob.owner_posts
    # []
    
    post = session.query(Post).get(1)
    print post.owner
    # <User: Alice>
    print post.last_editor
    # <User: Bob>
    

    现在,当您查询用户时,您可以询问该对象 user.owner_postsuser.editor_posts

    【讨论】:

      【解决方案2】:

      一般来说这是backref的命名问题。

      由于 1:n 关系有时会有点混乱,所以我设置了关系属性 总是在单个站点上,以避免混淆。

      那么 backref 名称总是单数的。并且关系属性总是在外键引用的类中。

      现在我对固定代码的建议:

      class Post(Base):
          last_editor_id = Column(BigInteger, ForeignKey('users.id'), nullable=True)
      
          owner_id = Column(BigInteger, ForeignKey('users.id'), nullable=False, index=True)
      
      
      class User(Base):
          '''This represents a user on the site'''
          __tablename__ = 'users'
          id = Column(BigInteger, primary_key=True, unique=True)
          name = Column(BigInteger, nullable=False)
          owned_posts = relationship('Post', backref='owner')
          edited_posts = relationship('Post', backref='last_editor')
      

      现在您可以使用User.owned_posts 获取所有拥有User 的帖子,以及使用Post.owner 获取帖子的所有所有者。与 last_edited 属性相同。

      有关更多信息,您可以阅读docs 如何建立关系

      【讨论】:

      • “这也不应该导致工作关系,因为你的关系引用必须在你所引用的类中,而不是在具有外键的类中”是错误的。我在另一个答案中扩展了我的示例以显示它有效。
      猜你喜欢
      • 2020-05-12
      • 1970-01-01
      • 2022-08-24
      • 2023-03-21
      • 1970-01-01
      • 2014-11-09
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      相关资源
      最近更新 更多