On Nov 13, 2012, at 7:59 PM, Gerald Thibault wrote:

> I have a base class which has two subclasses specified via a polymorphic 
> discriminator, and I'm wondering how to set things up so the returned results 
> are instances of the subclass, when I create an instance of the base class 
> and assign the relevant value to the discriminator column. Here's my example 
> code:

that's not how it usually works.  You'd create instances of the subclasses, and 
leave the discriminator column alone; SQLAlchemy assigns that.


>     
>     test1 = Test(type='one', name='a test')
>     session.add(test1)
>     print test1
> 
> This returns an instance of Test, not Test1, despite the discriminator 
> indicating that it should be cast as Test1.


OK here, you've said "test = Test()".  That is now the Python version of the 
class, SQLAlchemy has nothing to do with changing __class__ on your Test object 
or anything like that.   That object is going to stay just like it is, except 
for it getting a new primary key value.   SQLAlchemy's job here is to persist 
your row in the database and return it back for you later.  Here, the session 
hasn't even flushed any data, and you can see in your echo there's not any 
INSERT.   If you were to allow the row to go out to the database and come back, 
you'd see your class:

    test1 = Test(type='one', name='a test')
    session.add(test1)
    session.commit()  # flush + commit transaction
    session.close() # expunge the "Test()" object totally so we get a new one 
back

    print session.query(Test).one()

above, it's important that "test1" is removed from the Session totally, so that 
when we query again for that row, the Test object isn't returned; otherwise, it 
still points to that row.

However, the way it's supposed to work is, just use the classes as designed 
(note also, we use Session, or sessionmaker() - not create_session() which is a 
legacy function used for internal testing - see 
http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html for recommended usage 
patterns):

    from sqlalchemy.orm import Session
    session = Session(e)

    test1 = TestOne(name='a test')
    session.add(test1)
    print session.query(Test).one()   # autoflushes, then gets our TestOne back

> Also, if i create test1, and then do session.expunge_all, then immediately 
> requery for session.query(Site).get(1), the returned instance is of type 
> Test1, but trying to set the value for value1 yields 'Can't update table 
> using NULL for primary key value'.

works for me:


    test1 = TestOne(name='a test')
    session.add(test1)
    print session.query(Test).one()
    session.expunge_all()

    t = session.query(Test).one()
    t.value1 = "value1"
    session.commit()

output:

BEGIN (implicit)
INSERT INTO test (type, name) VALUES (?, ?)
('one', 'a test')
INSERT INTO test1 (id, value1) VALUES (?, ?)
(1, None)
SELECT test.id AS test_id, test.type AS test_type, test.name AS test_name, 
test1.id AS test1_id, test1.value1 AS test1_value1, test2.id AS test2_id, 
test2.value2 AS test2_value2 
FROM test LEFT OUTER JOIN test1 ON test.id = test1.id LEFT OUTER JOIN test2 ON 
test.id = test2.id
()
<__main__.TestOne object at 0x1014d7910>
SELECT test.id AS test_id, test.type AS test_type, test.name AS test_name, 
test1.id AS test1_id, test1.value1 AS test1_value1, test2.id AS test2_id, 
test2.value2 AS test2_value2 
FROM test LEFT OUTER JOIN test1 ON test.id = test1.id LEFT OUTER JOIN test2 ON 
test.id = test2.id
()
UPDATE test1 SET value1=? WHERE test1.id = ?
('value1', 1)
COMMIT



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

Reply via email to