davidr
davidr

Reputation: 35

Instantiating SQLAlchemy Base object with session query methods

Here's the simplest description of my SQLAlchemy model:

A Host object (subclass of Base), and a Network object (also Base). Host has a 1:Many relationship with the Network, and the Network object to be associated with the Host can be directly identified with the information given to the Host object as part of its initilization. (i.e. Host's __init__() is supplied with all the necessary information to be able to find the Network object with an SQLAlchemy session.

What I was considering doing was to pass the sqlalchemy session into the Host object so that Host.__init__() can query the database and find the proper Network object, i.e.

new_host = Host(sqlalchemy_sb_session, ip_address)

and make the association directly in __init__(). That seems very ugly to me, but I can't think of any other way to have the Host object be able to associate itself to a Network object.

I know this would work, but there must be a better way. How would anyone else solve this problem?

Upvotes: 0

Views: 1116

Answers (1)

van
van

Reputation: 76952

I would avoid passing Session object to the constructor of the class.
If it is so easy to find the Network from the Host, do you really need to keep the relation in the database? You could just have a properly with the SA lookup instead:

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

But obviously, some queries are just much easier if you have the Network object as well as one must ensure they exist. In this case the trick with Session.object_session can be used again, but it will not work for newly created objects which are not added to the session yet. In this case you should be able to use the SessionExtension object. The usage structure should be similar to below:

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())

Upvotes: 4

Related Questions