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空间顶部的对象。这个对象充当“根”,并且有一个显示该对象上一些数据的视图。

目标

  • 为根对象创建工厂。

  • 将其传递给配置程序。

  • 有一个在该对象上显示属性的视图。

步骤

  1. 我们将使用前面的步骤作为起点:

    $ cd ..; cp -r layout siteroot; cd siteroot
    $ $VENV/bin/python setup.py develop
    
  2. 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()
    
  3. 我们添加一个新文件 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
    
  4. 我们的观点 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)
    
  5. 重命名模板 siteroot/tutorial/templates/site.jinja2siteroot/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 %}
    
  6. 在中添加模板 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 %}
    
  7. 在中修改简单测试 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)
    
  8. 现在运行测试:

    1$ $VENV/bin/nosetests tutorial
    2..
    3----------------------------------------------------------------------
    4Ran 2 tests in 0.134s
    5
    6OK
    
  9. 运行 Pyramid 应用程序时使用:

    $ $VENV/bin/pserve development.ini --reload
    
  10. 在浏览器中打开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

  1. 启动时是否调用一次根工厂,还是每次请求都调用根工厂?做一个小小的改变来回答这个问题。答案对此有何影响?