2014-11-01 31 views
5

我有兩個非常簡單的模型。在我的Post模型中,應該有User表中的兩個關係。一個是郵件的所有者,另一個是郵件的最後編輯。它們可以是不同的值,但都是指相同的User表。sqlalchemy在關係上創建backref時出錯

我的模型建立這樣

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模型中僞造鑰匙?

回答

9

錯誤告訴你,你已經使用post作爲你的backrefs的一個名字,所有你需要做的就是給出backref的唯一名字。這裏有一個完整的例子 - 我已經爲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

+0

這fixies的映射問題,但他仍然沒有工作關係。 – muthan 2014-11-01 23:35:49

+0

嗯 - 它不工作,因爲Post類缺少主鍵,但關係正常。 – Doobeh 2014-11-02 00:35:34

+0

啊,沒關係,這是我的失敗。現在修復我的答案,以便我們有兩種解決方案。很高興知道它也適用於這種方式。 – muthan 2014-11-02 01:00:41

2

一般來說,這是一個命名Backref的問題。

由於1:n關係有時會令人困惑,因此我始終在單一網站上設置關係屬性 以避免混淆。

然後backref名稱總是單數。並且關係屬性始終位於外鍵所引用的Class中。

現在我的建議的固定代碼:

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_postsUser所有擁有職位,並與Post.owner後的所有業主。與last_edited屬性相同。

有關更多信息,你可以讀取docs如何建立關係

+0

「這也不應該導致工作關係,因爲你的關係參考必須在你正在學習的類中,而不是在Foreignkey「是錯誤的。我在其他答案中擴展了我的例子以顯示它的工作原理。 – Doobeh 2014-11-02 00:48:58

相關問題