Skip to main content
 首页 » 编程设计

python之如何使用 SQLAlchemy 获取引用的实体

2025年05月04日8落叶无声

我有一个关于 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,只有在你真的别无选择时才直接从外键分配或查询。我通过艰难的方式了解到这一点。