使用会话查询方法实例化SQLAlchemy Base对象
这是我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())