Chris McDonough wrote: > On 7/13/09 7:59 AM, Alberto Valverde wrote: >> Hello, >> >> I'm factoring out the core logic of a bunch of views into a generic CRUD >> "controller" for a bfg app which looks something like this: >> >> (..... snip ....) >> >> # some_views.py, module scope: >> class UserCrud(GenericCrud): >> # some template methods implemented >> >> # Instantiate a module-scope (stateless) singleton >> user_crud = UserCrud(some overrides like grid columns, form fields, >> etc...) >> >> # Now the work-arounds so the views can be registered I'd like to get >> rid of, >> # I'll explain below. >> user_member_view = user_crud.member_view >> user_collection_view = user_crud.collection_view >> >> This is wired up into the ZCA registry like this, configure.zcml: >> >> (.... snip....) >> Ok, the above zcml sucks a bit right now in the terseness department >> since there needs to be a directive for each request_type just to >> declare permissions (it wouldn't be needed otherwise since the >> "controller" takes care of dispatching) but I'll eventually write my >> custom zcml directive-processors which will take care of the >> bolier-plate when I find some time to learn how-to. > > Right. > >> >> Anyway, I'd like to remove the work-arounds I mentioned (the user_*_view >> aliases at module-scope) since the "view" directive doesn't seem able to >> import an instancemethod (or any non-module-global for that matter, I >> think). > > Yes, the resolver won't descend past module scope to find names. > > (.... snip ...) > I'm not sure if this helps, but instead of making a view out of an > instancemethod with a special name, maybe you could make N view > classes, one for each alias you currently have: > > (....snip ...)
Thanks for the suggestion. I've tried to separate the member/collection handling functionality into different classes (following the "classes as views" pattern mentioned in the docs) which I could register separately to avoid using instancemethods but it didn't work too well. Mainly because there is some configuration that they both need, for example, the list of fields since the "collection" controller needs it to configure the JS client and the "member" controller to make a jsonifiable dict out of instances. So I decided to just ignore this wart of my design for the moment and try to write a directive handler to reduce the configure.zcml bloat and it magically "fixed" both problems beautifully, plus it allowed me to remove the HTTP-method dispatching code from the controller since bfg now does it "for free": import inspect from zope.interface import Interface from zope.configuration.fields import GlobalObject from repoze.bfg.zcml import view as view_directive_handler class ICrudDirective(Interface): collection = GlobalObject( title=u"The interface or class of the collection.", required=True ) member = GlobalObject( title=u"The interface or class of the members of the collection.", required=True ) controller = GlobalObject( title=u"", description=u"The controller", required=True, ) def crud(_context, collection, member, controller): # If the controller is a class initialize it with no parameters. # At the point this is executed the app's registry is available so # controllers can use it to configure themselves if needed if inspect.isclass(controller): controller = controller() # Now we can get the instacemethods we need and pass them to bfg's # view handler directive. problem solved for for_, name, request_type, view, permission in [ (collection, 'config.js', 'GET', controller.config, 'view'), (collection, '', 'GET', controller.list, 'view'), (collection, '', 'POST', controller.create, 'create'), (member, '', 'GET', controller.show, 'view'), (member, '', 'PUT', controller.update, 'update'), (member, '', 'DELETE', controller.delete, 'delete'), ]: view_directive_handler( _context, permission=permission, for_=for_, view=view, name=name, request_type=request_type ) (meta.zcml to register all that omitted) So now I can do: # in views/user.py class UserController(CrudController): # bunch of class attributes + helper overrides to configure the UI, etc... # No aliases and no need to make an instance if the constructor take no params # then in configure.zcml <sigym:crud collection=".interfaces.IUsers" member=".interfaces.IUser" controller=".views.user.UserController" /> Wow, that was much easier than I expected; it took me more to write this email than implementing it ;) I am impressed. Next round will be mucking with the zcml directive handler so i can pass config. options to the "controller" when it initializes it... Alberto _______________________________________________ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev