一种对对象系统的url分派,它结合了路由和遍历的各个方面。
traject的Python项目详细描述
悲剧
简介
在web应用程序构建中,有两种主要的发布方式 对象到Web:路由和遍历。两者都是url的一种形式 分派:最后,调用函数或方法的结果是 URL中的模式。两种方法都有很大的不同, 但是。
在 路由中,从url模式到控制器(或 视图)调用以生成呈现的网页。网址 模式还用于从 然后可以传递。
例如url departments/10/employees/17 。URL 可能存在映射所有部门/*/employees/*的模式。 特定可调用的模式。此外,路由系统可以 用于声明参数 10` 和 17 应 从这个url获取并作为参数传递给 控制器。然后,程序员对控制器进行编程以检索 使用此信息从数据库中更正模型。此后 控制器使用这些模型中的信息来构造 视图的内容,例如用html呈现 模板。
在 遍历中,没有到控制器或 意见。相反,模型结构是在 URL。类似地,在python中可以遍历嵌套的 字典( d['a']['b']['c'] ),或属性( d.a.b.c )。在 最后,a 视图 将查找可以 打电话。视图可以是模型的特殊属性。更多 复杂的系统可用于将视图与模型分开。
url departments/10/employees/17 将被解析为一个视图 因为有一个包含 部门 模型对象。依次从a 部门 模型1 可以遍历到 employees 容器,从而允许 遍历到单个雇员,例如雇员17。最后一个 查找17号员工的视图,然后调用该视图。
路由通常与关系数据库结合使用, 通常通过对象关系映射器暴露给对象。 对于内存中的对象结构,遍历往往更方便。 或对象数据库。
路由有以下优点:
- 这是一种公开关系内容的好方法 自然嵌套。
- 模式注册表为开发人员提供了 应用程序中的URL模式。
- 这种方法在许多框架中都很常见。
遍历也有优点:
- 它是公开具有任意性的对象内容的好方法 嵌套。
- 模型驱动:对象带有它们的视图。这允许 由模型组成应用程序的开发人员,支持 陈述性方法。
- 位置感知:可以很容易地创建嵌套的对象结构 位置感知。每个模型都可以在 URL。这样可以方便地为任意 模型。此外,可以基于此声明权限 结构。
traject尝试在 单一系统。Traject:
- 看起来像一个路由系统并且熟悉路由 接近。
- 很适合公开关系模型。
- 允许开发人员显式声明URL映射。
- 支持任意嵌套,因为可以嵌套URL映射,并且 系统也很容易与正常的遍历相结合。
- 是模型驱动的。路由是到模型,而不是到视图或控制器。
- 位置感知。模型处于嵌套结构中,并且知道 它们的父级和名称,允许基于模型的安全声明 e模型的简易URL构造。
traject的一些潜在缺点是:
- 悲惨的事物期望它的模式有一定的规律性。它没有 允许某些包含多个变量的复杂url模式 单步(即 foo/<;bar-id>;-<;baz-id>; )。只有一个 每个url段允许变量。
- Traject需要为中的每个阶段构造或检索模型 用来构造嵌套结构的路由。这可能意味着 每个请求对数据库的更多查询。实际上,这通常是 由于结构中的父模型 视图逻辑通常需要。
- 在traject中,每个模型实例应该只有一个位置 在url结构中。这不仅允许将url解析为 模型,以及要为模型生成的url。如果你想 可以通过多个url访问同一个模型 有些困难。
URL模式
让我们考虑一个url模式字符串,它是一系列步骤 用斜线隔开:
>>> pattern_str = 'foo/bar/baz'
我们可以使用 parse将其分解为组件步骤 功能:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')
步骤也可能是变量。变量是以 冒号( : ):
>>> traject.parse('foo/:a/baz') ('foo', ':a', 'baz')
模式中允许有多个变量步骤:
>>> traject.parse('foo/:a/baz/:b') ('foo', ':a', 'baz', ':b')
模式中的变量名必须是唯一的:
>>> traject.parse('foo/:a/baz/:a') Traceback (innermost last): ... ParseError: URL pattern contains multiple variables with name: a
注册模式
在traject中,url路径的解析会产生一个模型。这个 然后,模型可以依次为其注册允许此操作的视图 要显示的模型。视图查找的工作方式取决于web 框架本身。
通过注册告诉traject哪个模型返回哪个路径 每个url模式的工厂函数。此工厂功能应该 创建或检索模型对象。
factory函数接收每个匹配的 无论哪种模式匹配的变量-工厂的签名 函数应该包含模式中的所有变量 匹配
让我们看一个例子。
这是我们要识别的URL模式:
>>> pattern_str = u'departments/:department_id/employees/:employee_id'
我们可以在这个url模式中看到两个参数: department\u id` 和 客户id
我们现在定义一个可能存储在数据库中的模型:
>>> class Employee(object): ... def __init__(self, department_id, employee_id): ... self.department_id = department_id ... self.employee_id = employee_id ... def __repr__(self): ... return '<Employee %s %s>' % (self.department_id, self.employee_id)
我们为这个url模式定义factory函数,以便 返回此模型的实例。本例中的参数将 部门ID 和员工ID :
>>> def factory(department_id, employee_id): ... return Employee(department_id, employee_id)
在本例中,factory函数只创建一个 employee 对象 在飞行中。在关系数据库的上下文中,它可以 根据提供的参数执行数据库查询。如果 factory返回 none ,这被解释为系统 无法匹配URL:找不到对象。
为了注册这个工厂函数,我们需要一个 模式,因此我们将创建一个:
>>> patterns = traject.Patterns()
需要为特定类注册模式,或者 ( zope.interface )接口。这就是多重模式 可以支持注册中心,每个注册中心都与特定的根目录关联 对象。在这种情况下,我们将注册一个类的模式 根目录 :
>>> pattern_str = 'foo/bar/baz'0
我们现在可以注册url模式和工厂:
>>> pattern_str = 'foo/bar/baz'1
解析路径
我们已经准备好解决问题。路径是url的一部分,例如 foo/bar/baz 。它看起来很像一个图案,但是 变量将已填写。
通过解析路径检索的模型将位于 位置。最终 他们的祖先将是一个特殊的根模型 都解决了。根模型本身不是由模式解析的:它 是解析所有模式的根。
我们创建一个根型号优先:
>>> pattern_str = 'foo/bar/baz'2
当路径被解析时,从模型到 根也被创建。可能没有特定的工厂功能 已为特定路径注册。在我们目前的注册中 确实存在这样的模式: 部门 , 部门/:department\u id 而且 部门/部门id/员工都没有工厂 已注册。
这些步骤将为它们注册一个默认的模型。 在解决模式时,我们需要提供一个特殊的默认工厂 它将在需要时生成默认模型。
让我们在这里建立一个默认工厂。工厂功能需要 能够处理任意数量的关键字参数 可能会提供参数:
>>> pattern_str = 'foo/bar/baz'3
现在我们有了默认工厂,可以尝试解析路径:
>>> pattern_str = 'foo/bar/baz'4
另一种 解析堆栈的方法允许我们解析堆栈 而不是名称(其中要解析的第一个名称位于 堆栈):
>>> pattern_str = 'foo/bar/baz'5
转换器
可以在模式中指定转换器。转换器是 将值转换为所需值并引发 如果不可能,则返回valueerror。python中的内置 int 是 转换器的示例。
在模式中指定一个转换器,该模式带有一个额外的冒号,然后 转换器标识符( int 在这种情况下):
>>> pattern_str = 'foo/bar/baz'6
Traject带有许多内置转换器:
- Unicode :默认转换器。尝试将输入转换为 Unicode值。如果未指定转换器,它将使用此转换器。
- str :尝试将输入转换为字符串。
- int :尝试将输入转换为整数。
- unicode list :尝试将输入转换为unicode列表 串。输入被分割成 ; 字符。
- strlist :尝试将输入转换为字符串列表。这个 输入在 ; 字符上分开。
- intlist :尝试将输入转换为整数列表。这个 输入在 ; 字符上分开。
我们现在注册模式:
>>> pattern_str = 'foo/bar/baz'7
我们看到该值确实已转换为整数:
>>> pattern_str = 'foo/bar/baz'8
可以使用 寄存器转换器注册新的转换器 方法。此方法有两个参数:转换器名称和 转换器功能。转换器功能应采用 参数并将其转换为所需的值。如果转换失败,则 应引发值错误。python int 函数是 有效转换器的示例。
位置
traject支持位置的概念。在我们找到一个模型后, 模型接收两个特殊属性:
>>> pattern_str = 'foo/bar/baz'9
- 父级:模型的父级。这是一个模型 匹配父路径(没有最后一步的路径)。
父母也会有一个父母,一直到 终极祖先,根。
我们可以查看之前检索到的对象来演示 祖先链:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')0
已经为沿途的每个步骤创建了默认对象 直到根。
使用路径
在混合的traject/traversal环境中,例如 查找是通过遍历完成的,能够解析 根据注册的模式直到不再 可能的。其余的步骤并没有被遵循,而是被假定为 以其他方式使用遍历系统。
consume方法将尽可能使用步骤,返回 那些还没有被消耗的步骤,那些被消耗的步骤, 它找到的对象:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')1
部门/1/某些视图不能完全使用Y按模式 部门/:部门id/员工/:员工id ,作为 某些视图与预期的员工不匹配
我们可以看到路径的哪些部分无法使用:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')2
路径的哪些部分被作为模式的一部分使用:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')3
我们设法使用的最后一个对象代表 1 :
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')4
方法consume\u stack的作用与stack相同:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')5
给模型定位
模型在遍历后自动给出它们的位置。那里 但是,在另一种情况下,给一个对象一个位置可以是 有用的。例如,我们可以从查询中检索一个对象,然后 希望构造指向它的URL,或检查它是否 位置相关权限。因此,Traject也提供 重建对象位置的功能。
为此,我们需要为每个模型注册一个特殊函数 类,它与工厂相反。给定一个模型实例,它 需要返回模式中使用的参数。因此,对于 以下模式:
>>> pattern_str = u'departments/:department_id/employees/:employee_id'
一个给定的模型,我们需要重建论点 部门id 和该模型中的员工id 。
这是一个为 员工 执行此操作的函数:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')7
当我们注册它时,我们还需要提供它可以使用的类 重新构造参数,在本例中, employee :
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')8
现在让我们构造一些员工:
>>> import traject >>> traject.parse(pattern_str) ('foo', 'bar', 'baz')9
它没有位置(没有名称或父项):
>>> traject.parse('foo/:a/baz') ('foo', ':a', 'baz')0
我们现在可以使用 locate 方法来定位它:
>>> traject.parse('foo/:a/baz') ('foo', ':a', 'baz')1
模型现在将具有 \u name\uu 和 \u parent\uu 属性:
>>> traject.parse('foo/:a/baz') ('foo', ':a', 'baz')2
全局模式注册表
因为模式注册中心足够聪明来区分 根,在许多情况下,只有一个全局 模式 注册表 是需要的。顶级功能已在 traject 要操作和使用此模式注册表的命名空间:
>>> traject.parse('foo/:a/baz') ('foo', ':a', 'baz')3