lets look at the SQL output with echo=True and see what we can observe:

BEGIN

INSERT INTO org (name, size_bytes) VALUES (?, ?)
['My Site', 0]

COMMIT

SELECT page.org_id AS page_org_id, page.id AS page_id
FROM page
WHERE ? = page.org_id ORDER BY page.oid
[1]

BEGIN

INSERT INTO page (org_id, content) VALUES (?, ?)
[1, 'My Home Page']

COMMIT

SELECT org.size_bytes AS org_size_bytes, org.name AS org_name, org.id
AS org_id
FROM org
WHERE org.name = ? ORDER BY org.oid
 LIMIT 1 OFFSET 0
['My Site']

1. firstly, you might notice that your "Org" object is not being
updated in the database at all when you do your second flush.  this
indicates that SQLAlchemy calculates which objects it needs to flush()
at the start of the flush() process, and is not going to pick up on
changes that occur *inside* the flush() (this would be impossible since
it is organizing all objects into a dependency graph before it does
anything).  So that is why your data is not in the database.

2. doing "del w" and then "w=Org.get_by(...)" returns to you the exact
same instance of Org that is still in the session.  From the session
docs, you'll see that every persistent object loaded by the session
stays there until explicitly removed, no matter what you do on the
outside.  if youd like to see your assertion fail, add a
"session.clear()" right before you do that second get_by(), and youll
see it come up.

3. while those first two things are easy, a third issue which is less
obvious (including to me) arises; that even if you try to re-flush()
that modified Org object again, the unit of work still does not save
it, because the "size_bytes" attribute gets its "dirty" flag reset
after the previous flush is complete.  there are ways to dig in and
un-reset it but that would be a little messy.

4. the solution here is not to use before_insert in this manner.  there
are many other ways to figure out "size_bytes" and many other ways to
get at it.

to determine "size_bytes" within the application, you just need to
calculate all at once:

org.size_bytes = sum([len(p.content) for p in org.pages])

if you want this to be "automatic", you can stick this on a
"before_insert" extension on Org's mapper, that way youll be assured
the value gets inserted:

class OrgExtension(MapperExtension):
    def before_insert(self, mapper, connection, instance):
        instance.size_bytes = sum([len(p.content) for p in
instance.pages if p.content is not None])

assign_mapper(context, Org, org_table, properties = {
   'pages' : relation(Page, backref='org')}, extension=OrgExtension())
assign_mapper(context, Page, page_table,
    properties = {'content' : deferred(page_table.c.content)})

w = Org(name="My Site")
w.pages.append(Page(content="My Home Page"))
session.flush()
assert w.size_bytes == len("My Home Page")  # passes
session.clear()
del w
w = Org.get_by(name="My Site")
assert w.size_bytes == len("My Home Page")  # passes!


--~--~---------~--~----~------------~-------~--~----~
 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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to