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. T 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 Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev