Yup, I understood your question :) Let me see if I can be a little more specific.

Even with inheritance and polymorphism, you still have two tables (entity and child) in the database. If you update just the value in the Child instance (which exists just in the child table), the entity table has nothing to do with it. If you "touch" only your Child instance attribute and none from the Parent instance, only its value (child) will be updated.

You can check if your parent instance is dirty after changing a value from child, it will probably return False:


*obj.value = "foobar"**
**p = session.query(Parent).filter(Parent.id == obj.id).one()**
**p in session.dirty # should return False. If returns True, then I think it is a bug**
**obj in session.dirty # shoud return True. go figure ...*


*IF* you want this to work without much effort, you should use updated_at in Child (which I agree if you think "you must be joking" or "you really must be joking", lol). If don't, polymorphism will not do that "automagically", at least IMHO. You can also check if there's a way to make the whole object dirty :)

Indeed it's a tricky situation, SA is expected by us to do this (and I think it may be our fault), but if it doesn't, the logic is also plausible.

I'll dig around the code too see what can be done.


Cheers,
Richard.


On 11/08/2013 09:34 AM, Bertrand Mathieu wrote:
Hello,

Thank you for your answer, but unless I miss something in your answer my problem has to do with polymorphic inheritance, it's not about relationship between 2 models. By inheritance "updated_at" is an attribute of any Child instance ( Child().updated_at exists).

I realize I didn't explained the example I joined:

(I also realize that Parent.__tablename__ is named 'entity', don't be confused)

class definitions:
class Parent(Base):
    __tablename__ = 'entity'
    __mapper_args__ = {'polymorphic_on': 'entity_type',
                      'with_polymorphic': '*',
                       }
    entity_type =  Column('entity_type', String(1000), nullable=True)

    id = Column('id', Integer(), primary_key=True)
    name =  Column('name', String(1000), default=u'')
    updated_at = Column(sa.DateTime,
                        default=datetime.utcnow,
                        onupdate=datetime.utcnow)


class Child(Parent):
    __tablename__ = 'child'
    __mapper_args__ = {'polymorphic_identity': 'Child'}
    id = Column(Integer,
                ForeignKey('entity.id', name='fk_inherited_entity_id'),
                primary_key=True)

    text = Column('text', String(1000), default=u'')

When run() is executed:

   obj = Child()
    session.add(obj)
    session.commit()

SQL emitted:
INSERT INTO entity (entity_type, name, updated_at) VALUES (?, ?, ?)
('Child', u'', '2013-11-08 10:27:18.886677')
INSERT INTO child (id, text) VALUES (?, ?)
(1, u'')
COMMIT

I change only one of Child's attributes:
obj.text = 'some text'
    session.commit()

SQL:
UPDATE child SET text=? WHERE child.id = ?
('some text', 1)
COMMIT

-> updated_at on table entity is not changed, so obj.updated_at is left untouched: don't want that.

But if I also change "name" (defined on Parent)
    obj.name = u'test'
    obj.text = 'some text'
    session.commit()

SQL:
UPDATE entity SET name=?, updated_at=? WHERE entity.id = ?
(u'test', '2013-11-08 10:27:18.891200', 1)
UPDATE child SET text=? WHERE child.id = ?
('some text', 1)
COMMIT

obj.updated_at is changed.


Le vendredi 8 novembre 2013 12:09:13 UTC+1, Richard Gerd Kuesters a écrit :

    I think the code is correct and is behaving correctly also --
    since you update just the child, the parent isn't touched (it
    already has data and was not changed in this session).

    What you could do is add an update event to your Child object:


    *def update_child(mapper, connection, target):**
    **    # target is your child updated**
    **    target.parent.updated_at = datetime.datetime.now()  #
    assuming you have mapped parent as a backref object or something**
    **    object_session(target).commit()**
    **
    **event.listen(Child, 'after_update', update_child)**
    *

    If you want the same after an insert or delete, you should declare
    other events[1] as well. I think there might be other ways to do
    that, but I usually use events for its flexibility.

    You can also use before_update to use the same session.commit()

    [1] http://docs.sqlalchemy.org/en/rel_0_8/orm/events.html
    <http://docs.sqlalchemy.org/en/rel_0_8/orm/events.html>

    Best regards,
    Richard.

    On 11/08/2013 08:38 AM, Bertrand Mathieu wrote:
    Hi,

    I have a set up class inheritance using joined table inheritance.
    I'm using sqlalchemy 0.8.2.

    The Parent class has a DateTime attribute "updated_at", with
    onupdate=datetime.utcnow.

    If I update only one of the Child's attributes, only "child"
    table is updated, parent.updated_at is not changed. If I change
    one of the Parent's attributes, then updated_at is updated as
    expected.

    Here's my questions:
    1) Am I missing something in my setup? is it normal or is it a bug?
    2) If this is normal, what is the right way to tell session that
    "parent.updated_at" should be modified too?

    Regards,
-- Bertrand

-- 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 <javascript:>.
    To post to this group, send email to sqlal...@googlegroups.com
    <javascript:>.
    Visit this group at http://groups.google.com/group/sqlalchemy
    <http://groups.google.com/group/sqlalchemy>.
    For more options, visit https://groups.google.com/groups/opt_out
    <https://groups.google.com/groups/opt_out>.

--
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+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.

--
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+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to