lessons learned: setting request.model

Andy Altepeter <[email protected]> Thu, 1 Nov 2007 14:57:41 -0500
Newsgroups gmane.comp.web.zope.silva.devel
Organization Bethel University
Message-ID <[email protected]>
Greetings,

I'm writing this email to express a "lesson learned" / "gotcha":

I just spent some time tracking down an obscure bug that was breaking things 
in the SNN News Item publish tab.  This bug surfaces if you attempt to 
future-publish a News Item (article or agenda item) by clicking "approve for 
future".  In Silva 2.0, you'll get an AttributeError: 
@@additional_status_action.  This bug was present in 1.6, but probably didn't 
surface as much.  It is possible (though not verified) that after approving 
for future, clicking actions on the subsequent page would come up with 
errors.

It turns out the problem was in NewsItem.get_intro.  There's a comment in 
there about "something" in the code needing request['model'] set.  I've 
needed to set (or replace) request['model'] a few times in various projects, 
and I've (re)learned a few important things:

1) ALWAYS save the model before running the code that needs a new model, and 
then RESTORE the saved model.  If there was no model previously, DELETE what 
you put in there.

2) The REQUEST object contains a LOT of scary magic.   Scary magic of the sort 
that request.model != request['model'].

In restricted python (PythonScripts), you can't set request.model.  BUT, you 
can set request['model'].  The latter puts 'model' in the 
dictionary "request.other".

In unrestricted, product code, you can do either.  But note that setting 
request.model DOES NOT put 'model' in the 'other' dictionary!  It sets an 
attribute on the request object with a name of 'model'.  That's a very 
important distiction!

The view registry (where 'model' typically gets set non-public processing), 
sets self.REQUEST['model'].  This placed 'model' in the 'other' dictionary, 
and as such 'model' is visible in the error log.

The get_intro code did used the alternate method, of setting 
self.REQUEST.model.  Since this is now an attribute of REQUEST, it isn't 
printed in the error log, and it is not obvious that there are now 
effectively TWO 'model' attributes in the REQUEST.

SilvaObject.view_version explicitly sets both, e.g.:
request.model = version
request.other['model'] = version

Note that I believe view_version is where the public rendering gets 
request.model.

Neither of these are meant to be called during other processing, as they 
overwrite the existing models.  

Well, there you have it.  I'm not sure what else to say other than to watch 
out when changing (or setting) request.model!

Andy