使用会话查询方法实例化SQLAlchemy Base对象

0 投票
1 回答
1098 浏览
提问于 2025-04-16 19:34

这是我SQLAlchemy模型最简单的描述:

有一个Host对象(是Base的子类),还有一个Network对象(也是Base)。Host和Network之间是一对多的关系,也就是说,一个Host可以关联多个Network。而要和Host关联的Network对象,可以通过在Host对象初始化时提供的信息直接找到。(也就是说,Host的__init__()方法会接收到所有必要的信息,这样就能通过SQLAlchemy会话找到对应的Network对象。)

我考虑的做法是把SQLAlchemy的会话传递给Host对象,这样Host.__init__()就可以查询数据库,找到合适的Network对象,也就是:

new_host = Host(sqlalchemy_sb_session, ip_address)

然后在__init__()中直接建立关联。不过我觉得这样做很不优雅,但我想不出其他方法让Host对象能够和Network对象关联起来。

我知道这样是可行的,但肯定有更好的方法。其他人会怎么解决这个问题呢?

1 个回答

4

我建议不要把Session对象传给类的构造函数。
如果从主机上找到网络这么简单,你真的有必要在数据库里保持这种关系吗?你可以通过SA查找来处理这个问题:

class Host(...):
    ...
    @property
    def Network(self):
        Session.object_session(self).query(Network).find(*my_search_criteria*)

不过,显然有些查询如果你同时拥有Network对象会简单很多,而且你还得确保这些对象是存在的。在这种情况下,可以再次使用Session.object_session这个技巧,但它对那些还没有添加到会话中的新创建对象是无效的。 在这种情况下,你应该能够使用SessionExtension对象。使用的结构应该和下面类似:

from sqlalchemy.orm.interfaces import SessionExtension
class TestSessionExtension(SessionExtension):
    def before_flush(self, session, flush_context, instances):
        for obj in session.new:
            if isinstance(obj, Host):
                # if the Host has no Network object assigned, then...
                # ... search-or-create the Network object using 'session'
                # ... assign this network object to the Host
Session = sessionmaker(bind=engine, extension=TestSessionExtension())

撰写回答