如何使用SQLAlchemy获取引用的实体?

时间:2013-07-05 09:29:22

标签: python sqlalchemy

我有一个关于SQLAlchemy中实体映射的问题。

我有一个瞬态对象,它已经包含一些持久对象的外键。我希望SQLAlchemy获取引用的对象并将它们分配给它们的关系属性。从SQLAlchemy文档中,我认为我必须在会话上使用合并操作来实现这一点。但在我的配置中,它不起作用。

这是证明我的问题的最低范例:

# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.orm import mapper
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker

class User(object):
    def __init__(self, id, name, fullname, password, best_friend_id=None):
        self.id = id
        self.name = name
        self.fullname = fullname
        self.password = password
        self.best_friend_id = best_friend_id

    def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)


class Dog(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
metadata = MetaData()

dogs_table = Table('dogs', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
)


users_table = Table('users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('fullname', String),
    Column('password', String),
    Column('best_friend_id', Integer, ForeignKey('dogs.id'))
)

metadata.create_all(engine)
mapper(User, users_table, properties={'best_friend': relationship(Dog, uselist=False)})
mapper(Dog, dogs_table)

dog = Dog(id=1, name='Hasso')
lordling = User(id=2, name='John', fullname='Miller', password='very_secret', best_friend_id=1)

session.add(dog)
session.commit()

merged_lordling = session.merge(lordling)
print str(merged_lordling.best_friend.name)

我希望merged_lordling.best_friend包含狗'Hasso'。但它仍然是None

1 个答案:

答案 0 :(得分:1)

我最近有点同样的问题。建立关系后,您应该直接将Dog实例分配给User.best_friend,而不是明确地使用外键。我不知道为什么会发生这种情况,但在调查类似的问题时,我意识到如果你这样做,SQLAlchemy不会填充关系属性,直到你刷新所有相关的实例。

所以,而不是:

dog = Dog(id=1, name='Hasso')
lordling = User(id=2, name='John', fullname='Miller', password='very_secret', 
                best_friend_id=1)

session.add(dog)

简单地说:

dog = Dog(id=1, name='Hasso')
lordling = User(id=2, name='John', fullname='Miller', password='very_secret', 
                best_friend=dog)

session.add(lordling)

甚至:

lordling = User(id=2, name='John', fullname='Miller', password='very_secret', 
                best_friend=Dog(id=1, name='Hasso'))
session.add(lordling)    

作为一般规则,请避免在建立关系时直接使用外键列。拥抱ORM,只有在没有其他选择时才直接从外键分配或查询。我学到了很难的方法。