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 ....)
>> #, 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.",

    member = GlobalObject(
        title=u"The interface or class of the members of the collection.",

    controller = GlobalObject(
        description=u"The controller",

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',,   'view'),
        (member,     '',          'PUT',     controller.update, 'update'),
        (member,     '',          'DELETE',  controller.delete, 'delete'),

(meta.zcml to register all that omitted)

So now I can do:

# in views/
class UserController(CrudController):
    # bunch of class attributes + helper overrides to configure the UI,

# No aliases and no need to make an instance if the constructor take no

# then in configure.zcml


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...


Repoze-dev mailing list

Reply via email to