在金字塔中创建动态 class 视图

Create dynamic class-views in pyramid

我正在尝试减少在 Pyramid 视图中编写的代码,并且正在尝试通过工厂函数来完成。

因此,我的 views.py 中没有这样的东西:

class MyView(object):
    def __init__(self, request):
        self.request = request

    @view_config(route_name='view', renderer='templates/view.pt')
    def get(self):
        return dict(msg='Hello!')

我试着用这样的东西代替:

def factory(cls_name, rtn, rndr, myfun):
    class Cls(object):
        def __init__(self, request):
            self.request = request

        @myfun(route_name=rtn, renderer=rndr)
        def get(self):
            return dict(msg='Hello!')

    Cls.__name__ = cls_name
    return Cls

MyView = factory('MyView', 'view', 'templates/view.pt', view_config)

原因很明显,我最终会得到许多可以利用相同 class 功能的 classes,我想减少我的代码编写。如果您要求我改为使用继承,那么我会被困在如何配置派生的 classes 以具有参数化装饰器(如 myfun)。本质上,我需要 C++ 中的模板之类的东西。

因此,即使上面的第二个片段没有产生任何错误,而且对我来说它似乎工作得很好,当我尝试在我的测试站点中 运行 它时(通过将第二个片段替换为第二个),金字塔不理解这些路线,所以我得到了 404 error。根据错误,我认为我的问题可能与金字塔如何解析 views.py 文件以查找 view_config 装饰器有关,但我不确定如何解决它。

我的__init__.py的主要功能是这样的:

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """      
    config = Configurator(settings=settings)
    config.add_route('view', '/')
    config.scan()
    return config.make_wsgi_app()

如有任何帮助,我们将不胜感激,在此先致谢!

您的代码无法正常工作的最可能原因是 Pyramid 在启动时执行的 scan 过程的细节,以查找和处理所有 @view_config 装饰器。一方面,@view_config 文档字符串说:

    ``view_config`` will work ONLY on module top level members
    because of the limitation of ``venusian.Scanner.scan``.

所以我猜要么你的 类 在启动过程中创建得太晚了,要么你动态生成的 类 中的某些东西让金星人感到困惑。如果您查看 venusian 的源代码,您可能会找到原因。

但是,我想指出的是,这种方法让我觉得有点递归...... Pyramid 中有一些方法可以在没有任何装饰器的情况下注册视图。然后 Pyramid 作者在其之上添加了一层 "syntax sugar" 以简化最常见的用例并能够通过简单地添加装饰器来注册视图。然后你开始与那些装饰器战斗,以便能够通过看起来像函数调用的方式注册视图:)

看看 pyramid.config.Configurator.add_view() - 它看起来已经很像你的 "factory function" 但如果你愿意,你可以围绕它编写一个简单的包装器。

class MyView(object):
    def __init__(self, request):
        self.request = request

    def get(self):
        return dict(msg='Hello!')

config.add_view(MyView, attr='get', route_name='view_cats', renderer='templates/view_cats.pt')
config.add_view(MyView, attr='get', route_name='view_dogs', renderer='templates/view_dogs.pt')