扩展现有 Pyramid 应用

如果A Pyramid 开发人员在构建应用程序时遵循了某些约束,第三方应该能够在不需要修改其源代码的情况下更改应用程序的行为。A的行为 Pyramid 遵循某些约束的应用程序可以 重写的扩展的 无需修改。

我们将在这里定义一些术语,以便于确定参与这种努力的各方。

开发商
原始应用程序开发人员。
积分器
另一个开发人员希望在意外的上下文中重用原始应用程序开发人员编写的应用程序。他们还可能希望在不更改原始应用程序的源代码的情况下修改原始应用程序。

“可扩展”和“可插拔”应用程序之间的区别

其他Web框架,如 Django ,宣传他们允许开发人员创建“可插拔的应用程序”。他们声称,如果您以某种方式创建一个应用程序,它将以合理、结构化的方式集成到另一个由第三方开发人员创建的任意编写的应用程序或项目中。

Pyramid 作为一个平台,并没有声称提供这样的功能。该平台不能保证您可以创建一个应用程序并将其打包,这样一个任意的集成器就可以将它作为一个更大的金字塔应用程序或项目中的子组件使用。金字塔并没有规定这种模式令人满意地工作所必需的约束。因为金字塔不是很“固执己见”,开发人员可以使用各种不同的模式和技术来构建应用程序。给定的金字塔应用程序可能会被特定的第三方集成器重用,因为集成器和原始开发人员可能共享类似的基础技术选择(例如使用特定的关系数据库或ORM)。但是同一个应用程序可能不能被不同的开发人员重用,因为他们做出了与原始开发人员不兼容的不同技术选择。

因此,“可插拔应用程序”的概念留给了金字塔之上构建的层,例如“CMS”层或“应用服务器”层。这些层倾向于提供必要的“意见”(例如要求存储层、模板系统和一个结构化的、有良好文档记录的注册特定URL映射到特定代码位的模式),这使得“可插入应用程序”的概念成为可能。因此,可插拔的应用程序不应该插入金字塔本身,而是应该插入写在金字塔顶部的系统。

虽然它不提供“可插拔的应用程序”,金字塔 does 提供一套丰富的机制,允许扩展单个现有应用程序。使用金字塔作为基础构建的框架可以使用这些特性。所有金字塔应用程序可能不是 可插拔的 但是所有的金字塔应用程序 可扩展的 .

构建可扩展应用程序的规则

如果要构建一个最大可扩展的 Pyramid 应用程序:作为开发人员,您应该考虑任何可重写的 imperative configuration 您已经创建了多个函数,可以通过 pyramid.config.Configurator.include() ,而不是作为对 Configuratormain 应用程序中的函数 __init__.py . 例如,而不是:

1
2
3
4
5
6
from pyramid.config import Configurator

if __name__ == '__main__':
    config = Configurator()
    config.add_view('myapp.views.view1', name='view1')
    config.add_view('myapp.views.view2', name='view2')

你应该把电话转到 add_view 外部(不可重复使用) if __name__ == '__main__' 块,并转换为可重用函数:

1
2
3
4
5
6
7
8
9
from pyramid.config import Configurator

if __name__ == '__main__':
    config = Configurator()
    config.include(add_views)

def add_views(config):
    config.add_view('myapp.views.view1', name='view1')
    config.add_view('myapp.views.view2', name='view2')

这样做允许集成器最大限度地重用与应用程序相关的配置语句,允许它们有选择地包含或排除从“覆盖包”中创建的配置函数。

或者您可以使用 ZCML 为了使配置具有可扩展性和可重写性。 ZCML 属于应用程序的声明可以根据需要由集成器以类似的方式重写和扩展。如果你只使用 ZCML 要配置您的应用程序,它将自动进行最大程度的扩展,而无需任何手动操作。见 pyramid_zcml 有关使用zcml的信息。

基本插点

使用 Pyramid路线意见资产 . 路由是使用 pyramid.config.Configurator.add_route() 方法。视图是使用 pyramid.config.Configurator.add_view() 方法。资产是由 Pyramid 使用 pkg_resources API,例如静态文件和模板 asset specification . 其他指令和配置器方法也处理路由、视图和资产。例如, add_handler 指令 pyramid_handlers 包添加了单个路由和一些视图。

扩展现有应用程序

扩展现有应用程序的步骤在很大程度上取决于应用程序是否使用配置修饰符或强制代码。

如果应用程序有配置装饰

你继承了一个 Pyramid 要扩展或重写的应用程序 pyramid.view.view_config 装饰工或其他 configuration decoration 装饰工。

如果你只是想 延伸 应用程序,您可以运行 scan 针对应用程序的包,然后添加注册更多视图或路由的附加配置。

1
2
3
if __name__ == '__main__':
    config.scan('someotherpackage')
    config.add_view('mypackage.views.myview', name='myview')

如果你想 覆盖 应用程序中的配置,您 may 需要运行 pyramid.config.Configurator.commit() 在执行原始包的扫描之后,添加附加配置,以注册执行覆盖的更多视图或路由。

1
2
3
4
if __name__ == '__main__':
    config.scan('someotherpackage')
    config.commit()
    config.add_view('mypackage.views.myview', name='myview')

完成后,您应该能够像其他任何应用程序一样扩展或重写应用程序(请参见 扩展应用程序

你也可以阻止 scan 通过省略任何呼叫 pyramid.config.Configurator.scan() 方法。这将导致附加到目标应用程序中对象的装饰器不做任何事情。此时,您需要将decorator中完成的所有配置转换为等效的强制配置或zcml,并将该配置或zcml添加到单独的python包中,如中所述。 扩展应用程序 .

扩展应用程序

要扩展或重写现有应用程序的行为,您需要创建一个新的包,其中包含旧包的配置,并且您可能需要创建要重写的类型(例如视图)的实现,这些类型在原始包中引用。

扩展现有应用程序的一般模式如下所示:

  • 创建一个新的python包。最简单的方法是创建一个新的 Pyramid 应用程序使用我们的 cookiecutter . 见 创建项目 更多信息。
  • 在新包中,根据需要创建包含视图和其他重写元素(如模板和静态资产)的python文件。
  • 将新包安装到与原始应用程序相同的python环境中(例如, $VENV/bin/pip install -e .$VENV/bin/pip install .
  • 改变 main 新包中的函数 __init__.py 包括原件 Pyramid 应用程序的配置功能通过 pyramid.config.Configurator.include() 语句或 scan .
  • 使用中的强制注册将新包中创建的新视图和资产连接起来。 main 功能 __init__.py 新应用程序的文件。这种接线应该发生 之后 包括旧应用程序的配置功能。这些注册将扩展或覆盖原始应用程序执行的任何注册。见 覆盖视图覆盖路由压倒一切的资产 .

覆盖视图

这个 view configuration 你所做的声明 覆盖 应用程序行为通常具有相同的 view predicate 属性作为要重写的原始属性。这些 <view> 声明将指向您创建的覆盖包中的“新”视图代码。新的视图代码本身通常是从原始应用程序复制和粘贴视图可调用文件的副本,只需稍作调整。

例如,如果原始应用程序具有以下内容 configure_views 配置方法:

1
2
def configure_views(config):
    config.add_view('theoriginalapp.views.theview', name='theview')

您可以重写由 configure_views 在覆盖包中,加载原始配置函数后:

1
2
3
4
5
6
7
from pyramid.config import Configurator
from originalapp import configure_views

if __name == '__main__':
    config = Configurator()
    config.include(configure_views)
    config.add_view('theoverrideapp.views.theview', name='theview')

在这种情况下, theoriginalapp.views.theview 永远不会执行视图。相反,一个新的视图, theoverrideapp.views.theview 将在请求情况指示时执行。

类似的模式可用于 延伸 应用程序 add_view 声明。只需针对其他一些谓词集注册一个新视图,以确保它所包含的URL在其他一些页面呈现中可用。

覆盖路由

路由设置当前通常按顺序调用 add_route() . 因为这些调用是相对彼此排序的,并且由于这种排序通常很重要,所以在执行覆盖时应该保留它们的相对排序。通常这意味着 复印 所有的 add_route 语句到重写包的文件中,并根据需要更改它们。然后排除任何 add_route 原始申请的声明。

压倒一切的资产

资产是文件系统中可在Python中访问的文件。 包裹 . 一整章都是关于资产的: 静态资产 . 本章中有一节 压倒一切的资产 . 本章的这一节详细介绍了如何使用 pyramid.config.Configurator.override_asset() 方法。添加这样 override_asset 调用覆盖包的 __init__.py 执行覆盖。