HI Chris

I a way you describing something simliar to what we have in zope2, in
that from a tal expression we have access to
(via acquisition) all of the portal tools etc...

I wonder if a couple of hi level functions could be put into the
namespace, (or the view for instance) that allow you
to lookup adapters and utilities in a simpler way, or alternately use
a view class and push the view handle into the template
and hang all of the extra api you need there. I have taken to useing
view classes most of the time and
always providing "view" as well as context and request.


On Sun, Sep 13, 2009 at 5:43 AM, Chris McDonough <chr...@plope.com> wrote:
> So I've been trying to puzzle out some issues, which might or might not
> be related to this topic.
> In KARL, we currently write all of our views something in the form of:
> def myview(context, request):
>    [ do stuff ]
>    api = TemplateAPI(context, request) # a utility class
>    return render_template_to_response('atemplate.pt', api=api,
>                                       foo=1, bar=2)
> In the template, we do things like "tal:replace="href api.context_url"
> and so on.  Basically, the KARL "api" object is a "garbage barge" of
> utility attributes and functions totally specific to the application
> itself.  There is nothing general about it.
> What I'd like to do is to be able to write a KARL view like this:
> def myview(context, request):
>    [ do stuff ]
>    return render_template_to_response('atemplate.pt', foo=1, bar=2)
> ... but still have some way of accessing the KARL "api" in the template.
>  In essence, I'd like to put the BFG templating system in charge of
> adding one or more globals that is accessible within the template.
> There's a half step towards this that's simple.  It'd be relatively easy
> to put both "context" and "request" into the names passed to all
> templates.  But this doesn't help us very much in the common case,
> because then we'd need to write a lot of hairy expressions to compute
> things based on those values.  Basically the template would assume the
> job of our current "API", which is not ideal.
> It'd be better if we could add some configuration that would one or more
> globals to a template's namespace.  For example, one configuration might
> look like (via ZCML):
>  <templatename name="api" component=".api.TemplateAPI"/>
> The ".api.TemplateAPI" class would accept, say, a context and a request
> (or just a request, as requests already have a context attribute), ala:
> class TemplateAPI(object):
>     def __init__(self, context, request):
>         self.context = context
>         self.request = request
>         self.context_url = model_url(context)
> At this point the name "api" would just be jammed into the template
> names on each template rendering and it could have both attributes and
> methods accessible via "api.whatever".
> At some point I had considered using a Chameleon expression prefix to
> separate these sorts of "builtin" names from the main template namespace
> names.  For example, instead of "tal:replace="href api.context_url",
> you'd access builtins via an expression type, e.g. "tal:replace="href
> api:context_url".  That bugged Malthe because it's essentially a "second
> "python:" expression type that happens to not use the "main" template
> namespace.  I'm not sure about it either, because it's obvious that
> you'll want to use the names passed to the template explicitly in those
> expressions too, and the semantics and implementation could get pretty
> confusing if you need to make that possible.
> Can anyone think of a better way of achieving this goal?  If we don't
> collectively come up with something better, I am apt to just allow folks
> to register factories via ZCML that produce something that is jamed into
> the main template namespace, ala the "templatename" ZCML directive
> above.  Any number of them will be registerable.  A conflict will occur
> during ZCML processing if two share the same name.  These functions, if
> they exist, will be called on each template rendering and their results
> will be jammed into the top-level namespace.
> Robert Marianski wrote:
>> On Mon, Aug 24, 2009 at 10:11:04PM -0400, Chris McDonough wrote:
>>> I like this.
>>> Some variations:
>>> - Have IOWrap be a multiadapter on context and request, so we can vary the
>>> o-wrap based on request type too (e.g. "IManagementRequest" vs. 
>>> "IRetailRequest").
>> Good idea. I'll go ahead and add this in.
>>> - If IOWrap can't be adapted, just return the result of the view (instead of
>>> throwing a component lookup error).
>> I'm kind of torn on this. On the one hand, I like that a specific
>> exception would get thrown, so it's easy to know when there's a
>> configuration problem and how to fix it. On the other, getting no wrap
>> is obvious itself, and may be better for users to initially see an
>> unwrapped page rather than seeing their applications explode.
>> I'd expect that there would typically be a catch-all owrap defined
>> anyway, so it's unlikely that this will be much of an issue in practice.
>> But in retrospect again, I think it's better to fail more gracefully by
>> showing an unwrapped view instead of an exception. I'll go ahead and
>> make this change too.
>>> Please forgive the digression, but this is physically sort of tied in: we 
>>> still
>>> need a good way to allow a set of "top level names" to be supplied to 
>>> templates.
>>>   So far, the best we could do for that pattern has been something like 
>>> ("api"
>>> is not a good name, I can't think of anything better, though):
>> Can you give an example use case for this? For the cases in my mind, I'd
>> prefer to push as much logic out into the owrap as possible, so that the
>> actual views don't need to worry about it. I can potentially see a lot
>> more ui reuse if this is possible. For example, I can write management
>> views against a dublin core interface, and this can be used in any
>> application now because it's not tied to any owrap macro.
>> The fuzzy area in my mind is a dynamic sidebar. I often have cases where
>> there's *always* a sidebar in the theme, maybe save for a couple of
>> pages, but the contents change depending on the view. It comes down to
>> whether you want to manage the contents of the sidebar as part of the
>> view, or part of the owrap, and I think this depends on how drastic the
>> changes themselves are.
>> I think having the owrap do some sort of lookup to figure out what goes
>> in the sidebar is more flexible. But in practice, I've found it more
>> annoying to work with it this way, because it's more convenient to
>> handle it in the view's template/logic, especially if it's varied on a
>> view to view basis.
>> Is this the sort of thing you have in mind?
>>> class TemplateAPI:
>>>     def __init__(self, context, request):
>>>         ... do stuff ...
>>> Then in a view:
>>> api = TemplateAPI(context, request)
>>> return render_template_to_response('templates/mytemplate.pt',
>>>                                      api=api)
>>> When the template needs access to "common" names, it then does e.g.
>>> tal:content="api.something".
>> I guess I don't exactly follow what the top level common names are. Are
>> they things like topnav, header, footer, where those are calculated
>> based on context and security?
>>> Malthe said it might be possible to register one or more new TAL expression
>>> types (each of which might represent a namespace) so templates could do
>>> something like tal:content="api:something" (note colon instead of dot) to 
>>> get
>>> top-level names instead.  The view would no longer need to pass an "api" to
>>> provide the template with access to very common top-level names.
>> I personally like this sort of thing. With zpt in a grok/plone setting,
>> I've found myself writing traversal adapters for things like checking
>> security, or application wide custom template "filters". It's much
>> easier to be able to use these in a template by using this sort of
>> syntax rather than passing them on through the view. For example:
>> <a tal:attributes="href model_url(context, request, 'edit')"
>>    tal:condition="context/has_permission:edit">Edit</a>
>> Maybe some sort of syntax for model_url would be convenient too :)
>> What do you guys typically do?
>>> However, computing the values for the top-level names often requires access 
>>> to
>>> stuff in the request or the context, and the current "render_template" APIs
>>> don't require that you pass either in to the view.
>>> I guess we could provide an alternate implementation of the template* APIs 
>>> (like
>>> render_template_to_response and get_template, etc) that must be passed the
>>> request (the request has access to the context too as request.context) as 
>>> the
>>> first argument if values for names needed to be computed based on those 
>>> bits of
>>> information.
>> That sounds reasonable to me.
>>> If views had access to top-level names like this, we could also just do 
>>> owraps
>>> the more traditional way (using METAL), if one of the names was e.g.
>>> "main_template".  I suppose the names would be computed via an adapter 
>>> lookup
>>> just like the rm.owrap stuff does now.
>> For cases where the owrap varies a lot from view to view, I think the
>> metal approach works well. But for times when the dynamicness of the
>> owrap can be easily calculated from the owrap, I think pushing it to the
>> owrap makes sense.
>>> That said, I don't think that approach is mutually exclusive with the 
>>> pagelet
>>> approach.  The pagelet approach is more generic: any templating language 
>>> could
>>> be used for the owrap or the wrapped view; the same can't be said for the
>>> top-level-name way.  Maybe some combination of both.
>> Definitely. Although imho, if you're using macros for the wrapping in
>> all your views, then you have less to gain by using an adapted owrap.
>> Robert
>>> On 8/24/09 2:14 AM, Robert Marianski wrote:
>>>> I was thinking about different ways to apply the owrap theme that's
>>>> typical for most applications.
>>>> I like the way that z3c.pagelet does it:
>>>> http://svn.zope.org/z3c.pagelet/trunk/
>>>> To summarize, views are registered through a different directive, and
>>>> then a layout is applied with a special directive. The advantage here is
>>>> that the views no longer specify their master template. It's configured
>>>> externally through zcml. This, theoretically anyway, allows more view
>>>> reuse since they can be registered with a separate owrap in a different
>>>> application without modification to the view code.
>>>> Anyway, I have a simple poc implementation for repoze.bfg.
>>>> $ svn co http://svn.repoze.org/playground/rmarianski/rm.owrap/trunk/ 
>>>> rm.owrap
>>>> $ cd rm.owrap
>>>> $ python bootstrap.py
>>>> $ bin/buildout
>>>> $ bin/test
>>>> $ bin/paster serve src/dummyapp/dummyapp.ini
>>>> Like z3c.pagelet, it adds a new directive for view registration. But
>>>> instead of a new directive for the layout, it just uses a plain adapter
>>>> to get the owrap. A new directive might be better because it would stand
>>>> out more in the zcml, but it was easier to do this way for a poc.
>>>> Robert
>>>> _______________________________________________
>>>> Repoze-dev mailing list
>>>> Repoze-dev@lists.repoze.org
>>>> http://lists.repoze.org/listinfo/repoze-dev
>>> _______________________________________________
>>> Repoze-dev mailing list
>>> Repoze-dev@lists.repoze.org
>>> http://lists.repoze.org/listinfo/repoze-dev
> _______________________________________________
> Repoze-dev mailing list
> Repoze-dev@lists.repoze.org
> http://lists.repoze.org/listinfo/repoze-dev
Repoze-dev mailing list

Reply via email to