2:有立地根的基本导线测量¶
将网站建模为具有操作的对象层次结构。
背景¶
Web应用程序具有定位数据并对该数据进行操作的URL。 Pyramid 支持将URL映射到python操作的两种方法:
更传统的方法 URL调度, 或*路线*
更面向对象的方法 traversal Zope推广
在本节中,我们将逐位介绍遍历。在此过程中,我们将尝试用遍历的方式来展示它是多么的简单和 Python 式的思考。
Traversal is easy, powerful, and useful.
使用Traversal,您可以将网站视为Python对象树,就像字典一样。例如::
http://example.com/company1/aFolder/subFolder/search
…只不过是:
>>> root['aFolder']['subFolder'].search()
为了消除遍历的一些秘密,我们从尽可能小的步骤开始:URL空间顶部的对象。这个对象充当“根”,并且有一个显示该对象上一些数据的视图。
目标¶
为根对象创建工厂。
将其传递给配置程序。
有一个在该对象上显示属性的视图。
步骤¶
我们将使用前面的步骤作为起点:
$ cd ..; cp -r layout siteroot; cd siteroot $ $VENV/bin/python setup.py develop
在
siteroot/tutorial/__init__.py
,创建一个根工厂,指向我们将要创建的模块中的函数:1from pyramid.config import Configurator 2 3from .resources import bootstrap 4 5 6def main(global_config, **settings): 7 config = Configurator(settings=settings, 8 root_factory=bootstrap) 9 config.include('pyramid_jinja2') 10 config.scan('.views') 11 return config.make_wsgi_app()
我们添加一个新文件
siteroot/tutorial/resources.py
有一个类作为我们站点的根,还有一个工厂返回它:1class Root(dict): 2 __name__ = '' 3 __parent__ = None 4 def __init__(self, title): 5 self.title = title 6 7 8def bootstrap(request): 9 root = Root('My Site') 10 11 return root
我们的观点
siteroot/tutorial/views.py
are now very different:1from pyramid.view import view_config 2 3 4class TutorialViews: 5 def __init__(self, context, request): 6 self.context = context 7 self.request = request 8 9 @view_config(renderer='templates/home.jinja2') 10 def home(self): 11 page_title = 'Quick Tutorial: Home' 12 return dict(page_title=page_title) 13 14 @view_config(name='hello', renderer='templates/hello.jinja2') 15 def hello(self): 16 page_title = 'Quick Tutorial: Hello' 17 return dict(page_title=page_title)
重命名模板
siteroot/tutorial/templates/site.jinja2
到siteroot/tutorial/templates/home.jinja2
并修改它:1{% extends "templates/layout.jinja2" %} 2{% block content %} 3 4 <p>Welcome to {{ context.title }}. Visit 5 <a href="{{ request.resource_url(context, 'hello') }}">hello</a> 6 </p> 7 8{% endblock content %}
在中添加模板
siteroot/tutorial/templates/hello.jinja2
:1{% extends "templates/layout.jinja2" %} 2{% block content %} 3 4<p>Welcome to {{ context.title }}. Visit 5<a href="{{ request.resource_url(context) }}">home</a></p> 6 7 8{% endblock content %}
在中修改简单测试
siteroot/tutorial/tests.py
:1import unittest 2 3from pyramid.testing import DummyRequest 4from pyramid.testing import DummyResource 5 6 7class TutorialViewsUnitTests(unittest.TestCase): 8 def test_home(self): 9 from .views import TutorialViews 10 11 request = DummyRequest() 12 title = 'Dummy Context' 13 context = DummyResource(title=title) 14 inst = TutorialViews(context, request) 15 result = inst.home() 16 self.assertIn('Home', result['page_title']) 17 18 19class TutorialFunctionalTests(unittest.TestCase): 20 def setUp(self): 21 from tutorial import main 22 app = main({}) 23 from webtest import TestApp 24 self.testapp = TestApp(app) 25 26 def test_hello(self): 27 result = self.testapp.get('/hello', status=200) 28 self.assertIn(b'Quick Tutorial: Hello', result.body)
现在运行测试:
1$ $VENV/bin/nosetests tutorial 2.. 3---------------------------------------------------------------------- 4Ran 2 tests in 0.134s 5 6OK
运行 Pyramid 应用程序时使用:
$ $VENV/bin/pserve development.ini --reload
在浏览器中打开http://localhost:6543/hello。
分析¶
我们的 __init__.py
有一个小的但重要的改变:我们用 根工厂. 根工厂是一个简单的函数,它执行一些工作并返回 resource tree .
在资源树中, Pyramid 可以将URL与对象和子对象匹配,并在视图中完成要执行的操作。通过容器的遍历是使用python的 __getitem__
dictionary protocol.
除了简单的python字典外,pyramid还提供服务。这些 location 服务需要更多的协议,而不仅仅是 __getitem__
. 也就是说,对象需要为 __name__
和 __parent__
.
在这一步中,我们的树有一个对象:根。这是我们的一个例子 Root
类。The next URL hop is hello
. Our root instance does not have an item in its dictionary named hello
,所以 Pyramid 寻找一个视图 name=hello
,找到我们的视图方法。
我们的 home
视图由 Pyramid 传递,此文件夹的实例为 context
. 然后,视图可以从作为URL焦点的对象中获取属性和其他数据。
现在到最明显的部分:没有更多的路线!以前我们编写了URL“替换模式”,它映射到一个路由。路由从模式中提取数据,并使这些数据可用于映射到该路由的视图。
相反,URL中的段在Python中成为对象标识符。
Extra Credit¶
启动时是否调用一次根工厂,还是每次请求都调用根工厂?做一个小小的改变来回答这个问题。答案对此有何影响?