Manuel Faux
Manuel Faux

Reputation: 2467

Session in association_proxy creator

I use SQLAlchemy 0.5 and Python 2.6.6.

I want to select or create a referred object within an association_proxy's creator. My problem is, that I need a session for this, but I don't know where to get this in the creator callback.

How can I use the session an object belongs to in one of its association proxy's creator?

What I've tried, which does not work

I've found session.object_session, but don't have any object in the callback, unless it is part of my ORM object. If it is part of my object, the caller won't be called as a method (the first argument is the value of the proxy, not the object's reference):

class Event(ManagerBase):

    # If association_proxy calls this, 'self' is the key, not the
    # reference to the calling instance.
    def _field_find_or_create(self, key, val):
        session = session.object_session(self)
        field = session.query(Field).filter_by(name=key).first()
        if not field:
            field = Field(name=key)

        return EventFieldValue(field=field, value=val)

    fields = association_proxy("field_values", "value",
                               creator=_field_find_or_create)

Can I pass the object itself to the creators function? In this case I could call object_session on this object.

My project uses several sessions, because of this I have to determine the concrete session on execution of the creator.

Upvotes: 3

Views: 589

Answers (2)

amleczko
amleczko

Reputation: 170

I think what you need is a validate method:

from sqlalchemy.orm import validates, object_session

class Event(ManagerBase):
   value = relationship(FieldValue)    
   fields = association_proxy("field_values", "value",
                              creator=lambda group: FieldValue(value=value))

   @validates("field_values") 
   def _validate_field_values(self, key, value): 
       session = object_session(self) 
       if session is not None: 
           v = value.value 
           with session.no_autoflush: 
               uvalue = session.query(FieldValue) \ 
                   .filter_by(name=a) \ 
                   .first() 
               if uvalue: 
                   session.expunge(value) 
                   return ugroup 
       return value

The credits goes to https://groups.google.com/forum/#!topic/sqlalchemy/RMDI1SnGhd0.

Upvotes: 1

pi.
pi.

Reputation: 21582

This problem persists in SQLAlchemy 0.7 as well. I've had the same problem in a slightly different context. Because the associationproxy is a Python descriptor and descriptors operate on the class level you can't give the creator function a reference to a bound method (which operate on the instance level).

I arrived at the following solution:

  1. within your creator function, create a new session from a global sessionmaker and fetch your objects
  2. expunge your fetched objects immediately from this temporary session
  3. close the session
  4. return your objects

My code looks like this:

def find_object(name):                                                                                                                                                                                    
    # Because we can't get a grip on the actual session we instead use a global
    # session for querying this instance.
    session = Session()
    obj = Model.query(session).filter_by(name=name).first()
    # We also have to dump the reference to that session, so the created object
    # can be used on other sessions.
    session.expunge(obj)
    # We don't need that session any more.
    session.close()
    return obj

Upvotes: 0

Related Questions