using an unmapped object to get the mapped object from a session

55 views
Skip to first unread message

Chris Withers

unread,
Jan 10, 2013, 3:35:37 AM1/10/13
to sqlal...@googlegroups.com
Hi All,

If I have an unmapped object which has had some attributes set on it,
what would be the best way to use that object to load a mapped object?

I didn't noticed a session.lookup(myobj) method ;-)

The specific semantics I'm looking for would be to find the rows, if
there's no rows, return None (or raise an exception...), if there's one,
return the mapped object, if there's more than one, raise an exception.

I was going to just write this myself (what's the best way to plug an
extra method on session nowadays, or should I just make it a class
method on a mixin?) but thought I'd ask here first...

...I was also curious as to how I can spot only attributes that have
been passed into the objects constructor, or set on it, to use in the
query while making sure not to use any defaults.

Thanks for all/any help!

Chris

--
Simplistix - Content Management, Batch Processing & Python Consulting
- http://www.simplistix.co.uk

Michael Bayer

unread,
Jan 10, 2013, 6:52:15 PM1/10/13
to sqlal...@googlegroups.com

On Jan 10, 2013, at 3:35 AM, Chris Withers wrote:

> Hi All,
>
> If I have an unmapped object which has had some attributes set on it, what would be the best way to use that object to load a mapped object?
>
> I didn't noticed a session.lookup(myobj) method ;-)


what is it looking up ? what's a "myobj" ?


Chris Withers

unread,
Jan 11, 2013, 2:17:31 AM1/11/13
to sqlal...@googlegroups.com, Michael Bayer
An unmapped instance of the mapped class.

Here's a unit test I'd like to have pass, although in this example
lookup is implemented as a method on the mapped class:

class LookupTests(TestCase):

def setUp(self):
Base = declarative_base()
class Model(Common, Base):
id = Column(Integer, primary_key=True)
value1 = Column(Integer, nullable=False)
value2 = Column(Integer, default=42)

self.Model = Model
registerSession(metadata=Base.metadata)

def test_simple(self):
session = getSession()
model1 = session.add(self.Model(id=1, value1=2, value2=3))

model2 = Model(value1=2).lookup(session)

self.assertTrue(model2 is model1)

cheers,

Michael Bayer

unread,
Jan 11, 2013, 10:26:12 AM1/11/13
to sqlal...@googlegroups.com

On Jan 11, 2013, at 2:17 AM, Chris Withers wrote:

> On 10/01/2013 23:52, Michael Bayer wrote:
>>
>> On Jan 10, 2013, at 3:35 AM, Chris Withers wrote:
>>
>>> Hi All,
>>>
>>> If I have an unmapped object which has had some attributes set on it, what would be the best way to use that object to load a mapped object?
>>>
>>> I didn't noticed a session.lookup(myobj) method ;-)
>>
>>
>> what is it looking up ? what's a "myobj" ?
>
> An unmapped instance of the mapped class.

yeah you don't want to have unmapped instances of mapped classes lying around. another approach perhaps ? since that practice is not supported.


Chris Withers

unread,
Jan 11, 2013, 1:37:38 PM1/11/13
to sqlal...@googlegroups.com, Michael Bayer
On 11/01/2013 15:26, Michael Bayer wrote:
>
>>> what is it looking up ? what's a "myobj" ?
>>
>> An unmapped instance of the mapped class.
>
> yeah you don't want to have unmapped instances of mapped classes lying around.

Why? They're just objects.

It's really handy having domain objects that can exist without
potentially ever having to know about a database...

What's the downside of having unmapped objects around?

Michael Bayer

unread,
Jan 11, 2013, 3:01:35 PM1/11/13
to sqlal...@googlegroups.com

On Jan 11, 2013, at 1:37 PM, Chris Withers wrote:

> On 11/01/2013 15:26, Michael Bayer wrote:
>>
>>>> what is it looking up ? what's a "myobj" ?
>>>
>>> An unmapped instance of the mapped class.
>>
>> yeah you don't want to have unmapped instances of mapped classes lying around.
>
> Why? They're just objects.
>
> It's really handy having domain objects that can exist without potentially ever having to know about a database...
>
> What's the downside of having unmapped objects around?

Beginning to suspect we have a terminology mismatch, an "unmapped" object of a "mapped class" implies you are creating objects from a class before you've mapped the class (that is, called mapper() on the class). Once you've mapped the class, it's no longer possible to get such an object unless you tear down all mappers. So these objects by definition are weird and awkward as they can only be created before your program has completed initialization, or if your program is tearing down mappers which is also not at all appropriate for any application except for extremely specific testing scenarios. If you're using declarative, it should not be possible to have an instance of an unmapped class, for a class that is later mapped, because the mapping is created at the time the class is created (which is as it should be).


Perhaps we're not talking about the same thing ? Do you just mean, objects that you aren't actually persisting in the database ? Totally different thing, you're referring to "transient" objects. These are mapped like anything else.

http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#sqlalchemy.orm.session.Session.enable_relationship_loading grants some support for that, depending on what you're trying to do. Or session.merge() will load the "persistent" version of an object, given a transient one with a particular primary key.



Chris Withers

unread,
Jan 11, 2013, 4:33:06 PM1/11/13
to sqlal...@googlegroups.com, Michael Bayer
On 11/01/2013 20:01, Michael Bayer wrote:
>
> On Jan 11, 2013, at 1:37 PM, Chris Withers wrote:
>
>> On 11/01/2013 15:26, Michael Bayer wrote:
>>>
>>>>> what is it looking up ? what's a "myobj" ?
>>>>
>>>> An unmapped instance of the mapped class.
>>>
>>> yeah you don't want to have unmapped instances of mapped classes lying around.
>>
>> Why? They're just objects.
>>
>> It's really handy having domain objects that can exist without potentially ever having to know about a database...
>>
>> What's the downside of having unmapped objects around?
>
> Beginning to suspect we have a terminology mismatch, an "unmapped" object of a "mapped class" implies you are creating objects from a class before you've mapped the class

Yep, terminology mismatch, that's why I gave the unit test example.

What's the correct way to refer to an instance of a mapped class but
that has never been anywhere near a session?

It's one of those I want to call the lookup method on with a session...

cheers,

Robert Forkel

unread,
Jan 11, 2013, 4:52:46 PM1/11/13
to sqlal...@googlegroups.com

Transient

--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To post to this group, send email to sqlal...@googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.

Chris Withers

unread,
Jun 20, 2013, 1:43:42 PM6/20/13
to sqlal...@googlegroups.com, Michael Bayer
Digging up an old thread, this time with (I hope) correct terminology:

If I have a transient object which has had some attributes set on it,
what would be the best way to use that object to load an object based on
those attributes from the database?

I didn't noticed a session.lookup(myobj) method ;-)

Here's a unit test I'd like to have pass, although in this example
lookup is implemented as a method on the mapped class:


class LookupTests(TestCase):

def setUp(self):
Base = declarative_base()
class Model(Common, Base):
id = Column(Integer, primary_key=True)
value1 = Column(Integer, nullable=False)
value2 = Column(Integer, default=42)

self.Model = Model
register_session(metadata=Base.metadata)

def test_simple(self):
session = get_session()

Michael Bayer

unread,
Jun 20, 2013, 3:43:12 PM6/20/13
to sqlal...@googlegroups.com

On Jun 20, 2013, at 1:43 PM, Chris Withers <ch...@simplistix.co.uk> wrote:

> Digging up an old thread, this time with (I hope) correct terminology:
>
> If I have a transient object which has had some attributes set on it, what would be the best way to use that object to load an object based on those attributes from the database?
>
> I didn't noticed a session.lookup(myobj) method ;-)


The mapper has all the identity key functions now:

from sqlalchemy import inspect

def lookup(session, obj):
mapper = inspect(obj).mapper
return session.query(mapper).get(mapper.primary_key_from_instance(obj))


a2 = A(id=1)
assert lookup(s, a2) is a1, "%r != %r" % (a1, a2)



Chris Withers

unread,
Jun 21, 2013, 1:49:21 PM6/21/13
to sqlal...@googlegroups.com, Michael Bayer
That's not what I'm after ;-)

The query needed to get the unit test to pass, as I would currently do
it, would be:

def lookup(self):
return session.query(Model).filter(
value1=self.value1
).one()

...but I'm looking to generalise that to any attribute that has been set
on the transient object on which lookup is called.

Michael Bayer

unread,
Jun 21, 2013, 3:34:50 PM6/21/13
to sqlal...@googlegroups.com

On Jun 21, 2013, at 1:49 PM, Chris Withers <ch...@simplistix.co.uk> wrote:

> On 20/06/2013 20:43, Michael Bayer wrote:
>>
>> On Jun 20, 2013, at 1:43 PM, Chris Withers<ch...@simplistix.co.uk> wrote:
>>
>>> Digging up an old thread, this time with (I hope) correct terminology:
>>>
>>> If I have a transient object which has had some attributes set on it, what would be the best way to use that object to load an object based on those attributes from the database?
>>>
>>> I didn't noticed a session.lookup(myobj) method ;-)
>>
>>
>> The mapper has all the identity key functions now:
>>
>> from sqlalchemy import inspect
>>
>> def lookup(session, obj):
>> mapper = inspect(obj).mapper
>> return session.query(mapper).get(mapper.primary_key_from_instance(obj))
>>
>>
>> a2 = A(id=1)
>> assert lookup(s, a2) is a1, "%r != %r" % (a1, a2)
>
> That's not what I'm after ;-)
>
> The query needed to get the unit test to pass, as I would currently do it, would be:
>
> def lookup(self):
> return session.query(Model).filter(
> value1=self.value1
> ).one()
>
> ...but I'm looking to generalise that to any attribute that has been set on the transient object on which lookup is called.

oh, it's not the primary key. Well then you'd need to figure out what attributes you care about. If it's all attributes, then loop through inspect(obj).attrs and build up a filter() function:

crit = []
cls = type(obj)
for key in inspect(obj).mapper.attrs:
crit.append(getattr(cls, key) == getattr(obj, key))

return and_(*crit)




>
> cheers,
>
> Chris
>
> --
> Simplistix - Content Management, Batch Processing & Python Consulting
> - http://www.simplistix.co.uk
>
> --
> You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.
> To post to this group, send email to sqlal...@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Reply all
Reply to author
Forward
0 new messages