Hello Pylons !

as we all know, a plain jane Pylons controller typically takes a form  
like this:

class HelloController(BaseController):
     def index(self):
         return render_response("/hello_world.html")

where "index()" returns a "Response" object, that contains the fully  
rendered text of "hello_world.html".

When combining a controller with SQLAlchemy, the need to ensure that  
the session is flush()ed becomes important.  I see on the site theres  
a description of putting the session create/flush() pair at the WSGI  
request level, for example.

One pretty handy way to mark a controller method as "needs flush" or  
"transactional" is through a decorator, like this:

class HelloController(BaseController):
     @flush_session
     def index(self):
         obj = session_context.current.query(Obj).get(1)
         obj.foo = 'bar'
         return render_response("/hello_world.html", obj=obj)

where the "flush_session" decorator is doing something like  
(extraneous decoration stuff removed):

def decorate(func):
     session = session_context.current
     try:
         response = func()
         session.flush()
         return response
     finally:
         session.clear()

So above, "response" is the return value of "render_response()"  
inside of "index()", i.e. a Response object.

Similar approaches have been taken with "transactional" methods, i.e.  
begin a transaction, run the method, then commit.

however, what is wrong with these !

basically, that the full content of the response is being rendered  
before the flush()/commit() takes place.  Now, even though it hasnt  
been sent *out* yet, and its only mildly wasteful to throw away the  
response in the case the flush fails, *the flush process generates  
new information*, such as new primary key values, column defaults,  
etc., which its extremely likely that the response will depend on  
(such as , "User "${user.name}" Saved.  Click <a href="/foo?user_id=$ 
{user.id}">here</a> to view your new user.").

So my instinct is to modify this pattern to "defer" the response.   
the controller becomes this:

class HelloController(BaseController):
     @flush_session
     def index(self):
         obj = session_context.current.query(Obj).get(1)
         obj.foo = 'bar'
         return lambda: render_response("/hello_world.html", obj=obj)

and the decorator this:

def decorate(func):
     session = session_context.current
     try:
         response = func()
         session.flush()
         assert callable(response), "Controller response is not a  
callable"
         return response()
     finally:
         session.clear()

where above, the render_response() call takes place *after* the  
session has been flushed, where it will only occur if the flush was  
successful and will have full access to any flush-generated state.    
my only issue with the above is that it looks dorky, and also is a  
little inconvenient and non-intuitive (although the decorator can  
check that the return value is a callable to enforce the pattern).

So, question time.

- Has anyone else had this problem ?  or is this not a problem ?

- is there some obvious or non-obvious way to do this more cleanly?

- if the answers are yes/no/no, would it make sense to add "deferred  
render" functionality to Pylons' response mechanism ? (and possibly  
for things like redirect_to(), etc?)  the implementation would be  
something along the lines of a DeferredResponse, or Response taking a  
callable as an argument, or something along those lines.   then some  
other part of Pylons would have to call render() or something similar  
on the response object to actually produce the content.  If there  
were Response /DeferredReponse, Response.render() maybe could return  
"self", where DeferredResponse.render() could return "self.callable 
()", which is then a Response itself.

if Pylons supported "deferred" response objects natively, this would  
be more analgous to how a system like Java Struts does it; the return  
value of a controller is not anything rendered at all, its just an  
ActionForward object which contains *instructions* on how to render  
the response.  all sorts of J2EE/spring transactional managers can  
cleanly wrap themselves around such a pattern, so that when the page  
is being rendered, all data has been committed to the database and  
all database-related state changes and new data have been produced.








--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to