3:遍历层次结构

Objects with subobjects and views, all via URLs.

背景

2:有立地根的基本导线测量

在这一步中,我们保持简单,但建立一个基本的层次结构:

1/
2   doc1
3   doc2
4   folder1/
5      doc1

目标

  • 使用Python对象的多级嵌套层次结构。

  • 展示如何 __name____parent__

  • 使用在请求之间持续的对象。

步骤

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

    $ cd ..; cp -r siteroot hierarchy; cd hierarchy
    $ $VENV/bin/python setup.py develop
    
  2. Provide a richer set of objects in hierarchy/tutorial/resources.py

     1class Folder(dict):
     2    def __init__(self, name, parent, title):
     3        self.__name__ = name
     4        self.__parent__ = parent
     5        self.title = title
     6
     7
     8class Root(Folder):
     9    pass
    10
    11
    12class Document(object):
    13    def __init__(self, name, parent, title):
    14        self.__name__ = name
    15        self.__parent__ = parent
    16        self.title = title
    17
    18# Done outside bootstrap to persist from request to request
    19root = Root('', None, 'My Site')
    20
    21
    22def bootstrap(request):
    23    if not root.values():
    24        # No values yet, let's make:
    25        # /
    26        #   doc1
    27        #   doc2
    28        #   folder1/
    29        #      doc1
    30        doc1 = Document('doc1', root, 'Document 01')
    31        root['doc1'] = doc1
    32        doc2 = Document('doc2', root, 'Document 02')
    33        root['doc2'] = doc2
    34        folder1 = Folder('folder1', root, 'Folder 01')
    35        root['folder1'] = folder1
    36
    37        # Only has to be unique in folder
    38        doc11 = Document('doc1', folder1, 'Document 01')
    39        folder1['doc1'] = doc11
    40
    41    return root
    
  3. hierarchy/tutorial/views.py

     1from pyramid.location import lineage
     2from pyramid.view import view_config
     3
     4
     5class TutorialViews:
     6    def __init__(self, context, request):
     7        self.context = context
     8        self.request = request
     9        self.parents = reversed(list(lineage(context)))
    10
    11    @view_config(renderer='templates/home.jinja2')
    12    def home(self):
    13        page_title = 'Quick Tutorial: Home'
    14        return dict(page_title=page_title)
    15
    16    @view_config(name='hello', renderer='templates/hello.jinja2')
    17    def hello(self):
    18        page_title = 'Quick Tutorial: Hello'
    19        return dict(page_title=page_title)
    
  4. 更新 hierarchy/tutorial/templates/home.jinja2 查看模板:

     1{% extends "templates/layout.jinja2" %}
     2{% block content %}
     3
     4  <ul>
     5    <li><a href="/">Site Folder</a></li>
     6    <li><a href="/doc1">Document 01</a></li>
     7    <li><a href="/doc2">Document 02</a></li>
     8    <li><a href="/folder1">Folder 01</a></li>
     9    <li><a href="/folder1/doc1">Document 01 in Folder 01</a></li>
    10  </ul>
    11
    12  <h2>{{ context.title }}</h2>
    13
    14  <p>Welcome to {{ context.title }}. Visit
    15    <a href="{{ request.resource_url(context, 'hello') }}">hello</a>
    16  </p>
    17
    18{% endblock content %}
    
  5. 这个 hierarchy/tutorial/templates/breadcrumbs.jinja2

    1{% for p in view.parents %}
    2<span>
    3  <a href="{{ request.resource_url(p) }}">{{ p.title }}</a>
    4>> </span>
    5{% endfor %}
    
  6. Update the tests in hierarchy/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_view(self):
     9        from .views import TutorialViews
    10
    11        request = DummyRequest()
    12        title = 'Dummy Context'
    13        context = DummyResource(title=title, __name__='dummy')
    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_home(self):
    27        result = self.testapp.get('/', status=200)
    28        self.assertIn(b'Site Folder', result.body)
    
  7. 现在运行测试:

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

    $ $VENV/bin/pserve development.ini --reload
    
  9. 在浏览器中打开http://localhost:6543/。

分析

__name__ as an identifier on each child, and __parent__ as a reference to the parent. The template used now shows different information based on the object URL to which you traversed.

@view_config can set a "default" view on a context by omitting the @name 属性。Thus, if you visit http://localhost:6543/folder1/

Extra Credit

  1. resources.py root out to global scope. 为什么?

  2. 如果你去一个不存在的资源, Pyramid 会优雅地处理它吗?

  3. 如果您请求一个资源的默认视图,但未配置任何视图, Pyramid 会处理得当吗?