Michael Merickel
2017-06-18 75c30dfe18b26ca04efae2acbe35052fa0d93ed6
commit | author | age
93a7a1 1 .. _wiki_basic_layout:
SP 2
e53e13 3 ============
CM 4 Basic Layout
5 ============
6
beb4f1 7 The starter files generated by the ``zodb`` cookiecutter are very basic, but
b743bb 8 they provide a good orientation for the high-level patterns common to most
34a913 9 :term:`traversal`-based (and :term:`ZODB`-based) :app:`Pyramid` projects.
e53e13 10
CM 11
34a913 12 Application configuration with ``__init__.py``
SP 13 ----------------------------------------------
e53e13 14
b3b713 15 A directory on disk can be turned into a Python :term:`package` by containing
CM 16 an ``__init__.py`` file.  Even if empty, this marks a directory as a Python
f5a9a5 17 package.  We use ``__init__.py`` both as a marker, indicating the directory in
SP 18 which it's contained is a package, and to contain application configuration
34a913 19 code.
b3b713 20
cfb2b5 21 When you run the application using the ``pserve`` command using the
34a913 22 ``development.ini`` generated configuration file, the application
f5a9a5 23 configuration points at a setuptools *entry point* described as
34a913 24 ``egg:tutorial``.  In our application, because the application's ``setup.py``
SP 25 file says so, this entry point happens to be the ``main`` function within the
f5a9a5 26 file named ``__init__.py``.
b3b713 27
f5a9a5 28 Open ``tutorial/__init__.py``.  It should already contain the following:
SP 29
30 .. literalinclude:: src/basiclayout/tutorial/__init__.py
31   :linenos:
32   :language: py
b3b713 33
c44c40 34 #. *Lines 1-3*.  Perform some dependency imports.
b3b713 35
34a913 36 #. *Lines 6-8*.  Define a :term:`root factory` for our Pyramid application.
b3b713 37
34a913 38 #. *Line 11*.  ``__init__.py`` defines a function named ``main``.
SP 39
40 #. *Line 14*.  We construct a :term:`Configurator` with a root
41    factory and the settings keywords parsed by :term:`PasteDeploy`.  The root
46d17b 42    factory is named ``root_factory``.
b3b713 43
909ae0 44 #. *Lines 15 and 16*.  Get the settings and use an explicit transaction transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle.
SP 45
46 #. *Line 17*.  Include support for the :term:`Chameleon` template rendering
404b28 47    bindings, allowing us to use the ``.pt`` templates.
MM 48
909ae0 49 #. *Line 18*.  Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.python.org/pypi/transaction>`_ package.
beb4f1 50
909ae0 51 #. *Line 19*.  Include support for ``pyramid_retry`` to retry a request when transient exceptions occur.
beb4f1 52
909ae0 53 #. *Line 20*.  Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application.
SP 54
55 #. *Line 21*.  Register a "static view", which answers requests whose URL
34a913 56    paths start with ``/static``, using the
8aa8a8 57    :meth:`pyramid.config.Configurator.add_static_view` method.  This
2a5ae0 58    statement registers a view that will serve up static assets, such as CSS
CM 59    and image files, for us, in this case, at
60    ``http://localhost:6543/static/`` and below.  The first argument is the
61    "name" ``static``, which indicates that the URL path prefix of the view
08c221 62    will be ``/static``.  The second argument of this tag is the "path",
0694f0 63    which is a relative :term:`asset specification`, so it finds the resources
CM 64    it should serve within the ``static`` directory inside the ``tutorial``
beb4f1 65    package.  Alternatively the cookiecutter could have used an *absolute* asset
49d823 66    specification as the path (``tutorial:static``).
b3b713 67
beb4f1 68 #. *Line 19*.  Perform a :term:`scan`.  A scan will find :term:`configuration
49d823 69    decoration`, such as view configuration decorators (e.g., ``@view_config``)
0694f0 70    in the source code of the ``tutorial`` package and will take actions based
CM 71    on these decorators.  We don't pass any arguments to
72    :meth:`~pyramid.config.Configurator.scan`, which implies that the scan
73    should take place in the current package (in this case, ``tutorial``).
beb4f1 74    The cookiecutter could have equivalently said ``config.scan('tutorial')``, but
0694f0 75    it chose to omit the package name argument.
2a5ae0 76
beb4f1 77 #. *Line 20*.  Use the
d7f259 78    :meth:`pyramid.config.Configurator.make_wsgi_app` method
b3b713 79    to return a :term:`WSGI` application.
e53e13 80
34a913 81 Resources and models with ``models.py``
2a5ae0 82 ---------------------------------------
e53e13 83
a5ffd6 84 :app:`Pyramid` uses the word :term:`resource` to describe objects arranged
CM 85 hierarchically in a :term:`resource tree`.  This tree is consulted by
86 :term:`traversal` to map URLs to code.  In this application, the resource
87 tree represents the site structure, but it *also* represents the
b743bb 88 :term:`domain model` of the application, because each resource is a node
a5ffd6 89 stored persistently in a :term:`ZODB` database.  The ``models.py`` file is
beb4f1 90 where the ``zodb`` cookiecutter put the classes that implement our
49d823 91 resource objects, each of which also happens to be a domain model object.
e53e13 92
CM 93 Here is the source for ``models.py``:
94
f5a9a5 95 .. literalinclude:: src/basiclayout/tutorial/models.py
SP 96   :linenos:
97   :language: python
e53e13 98
b0b299 99 #. *Lines 4-5*.  The ``MyModel`` :term:`resource` class is implemented here.
49d823 100    Instances of this class are capable of being persisted in :term:`ZODB`
2a5ae0 101    because the class inherits from the
CM 102    :class:`persistent.mapping.PersistentMapping` class.  The ``__parent__``
103    and ``__name__`` are important parts of the :term:`traversal` protocol.
beb4f1 104    By default, set these to ``None`` to indicate that this is the
2a5ae0 105    :term:`root` object.
e53e13 106
b0b299 107 #. *Lines 8-14*.  ``appmaker`` is used to return the *application
e53e13 108    root* object.  It is called on *every request* to the
fd5ae9 109    :app:`Pyramid` application.  It also performs bootstrapping by
e53e13 110    *creating* an application root (inside the ZODB root object) if one
34a913 111    does not already exist.  It is used by the ``root_factory`` we've defined
b25335 112    in our ``__init__.py``.
e53e13 113  
34a913 114    Bootstrapping is done by first seeing if the database has the persistent
SP 115    application root.  If not, we make an instance, store it, and commit the
116    transaction.  We then return the application root object.
e53e13 117
2a5ae0 118 Views With ``views.py``
CM 119 -----------------------
120
beb4f1 121 Our cookiecutter generated a default ``views.py`` on our behalf.  It
2a5ae0 122 contains a single view, which is used to render the page shown when you visit
CM 123 the URL ``http://localhost:6543/``.
124
125 Here is the source for ``views.py``:
126
f5a9a5 127 .. literalinclude:: src/basiclayout/tutorial/views.py
SP 128   :linenos:
129   :language: python
2a5ae0 130
CM 131 Let's try to understand the components in this module:
132
133 #. *Lines 1-2*. Perform some dependency imports.
134
b0b299 135 #. *Line 5*.  Use the :func:`pyramid.view.view_config` :term:`configuration
2a5ae0 136    decoration` to perform a :term:`view configuration` registration.  This
CM 137    view configuration registration will be activated when the application is
138    started.  It will be activated by virtue of it being found as the result
0694f0 139    of a :term:`scan` (when Line 14 of ``__init__.py`` is run).
2a5ae0 140
CM 141    The ``@view_config`` decorator accepts a number of keyword arguments.  We
142    use two keyword arguments here: ``context`` and ``renderer``.
143
144    The ``context`` argument signifies that the decorated view callable should
145    only be run when :term:`traversal` finds the ``tutorial.models.MyModel``
146    :term:`resource` to be the :term:`context` of a request.  In English, this
147    means that when the URL ``/`` is visited, because ``MyModel`` is the root
148    model, this view callable will be invoked.
149
150    The ``renderer`` argument names an :term:`asset specification` of
0694f0 151    ``templates/mytemplate.pt``.  This asset specification points at a
CM 152    :term:`Chameleon` template which lives in the ``mytemplate.pt`` file
2a5ae0 153    within the ``templates`` directory of the ``tutorial`` package.  And
CM 154    indeed if you look in the ``templates`` directory of this package, you'll
155    see a ``mytemplate.pt`` template file, which renders the default home page
0694f0 156    of the generated project.  This asset specification is *relative* (to the
49d823 157    view.py's current package).  Alternatively we could have used the
0694f0 158    absolute asset specification ``tutorial:templates/mytemplate.pt``, but
CM 159    chose to use the relative version.
2a5ae0 160
CM 161    Since this call to ``@view_config`` doesn't pass a ``name`` argument, the
162    ``my_view`` function which it decorates represents the "default" view
163    callable used when the context is of the type ``MyModel``.
164
b0b299 165 #. *Lines 6-7*.  We define a :term:`view callable` named ``my_view``, which
2a5ae0 166    we decorated in the step above.  This view callable is a *function* we
beb4f1 167    write generated by the ``zodb`` cookiecutter that is given a
2a5ae0 168    ``request`` and which returns a dictionary.  The ``mytemplate.pt``
CM 169    :term:`renderer` named by the asset specification in the step above will
170    convert this dictionary to a :term:`response` on our behalf.
171
172    The function returns the dictionary ``{'project':'tutorial'}``.  This
173    dictionary is used by the template named by the ``mytemplate.pt`` asset
174    specification to fill in certain values on the page.
175
b25335 176 Configuration in ``development.ini``
CM 177 ------------------------------------
2a5ae0 178
beb4f1 179 The ``development.ini`` (in the ``tutorial`` :term:`project` directory, as
SP 180 opposed to the ``tutorial`` :term:`package` directory) looks like this:
2a5ae0 181
9a8a21 182 .. literalinclude:: src/basiclayout/development.ini
f5a9a5 183   :language: ini
2a5ae0 184
14ffa6 185 Note the existence of a ``[app:main]`` section which specifies our WSGI
3d338e 186 application.  Our ZODB database settings are specified as the
CM 187 ``zodbconn.uri`` setting within this section.  This value, and the other
34a913 188 values within this section, are passed as ``**settings`` to the ``main``
2a5ae0 189 function we defined in ``__init__.py`` when the server is started via
cfb2b5 190 ``pserve``.