我有一个关于 SQLAlchemy 中实体映射的问题。
我有一个临时对象,它已经包含一些持久对象的外键。我希望 SQLAlchemy 获取引用的对象并将它们分配给它们的关系属性。从 SQLAlchemy 文档中,我认为我必须在 session 上使用合并操作来实现这一点。但在我的配置中,它不起作用。
这是演示我的问题的最小示例:
# -*- 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。
请您参考如下方法:
最近我也遇到了同样的问题。建立关系后,您应该直接将 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,只有在你真的别无选择时才直接从外键分配或查询。我通过艰难的方式了解到这一点。
