1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
============
Basic Layout
============
The starter files generated by the ``bfg_zodb`` template are basic,
but they provide a good orientation for the high-level patterns common
to most :term:`traversal` -based :mod:`repoze.bfg` (and :term:`ZODB`
based) projects.
``__init__.py``
---------------
A directory on disk can be turned into a Python :term:`package` by
containing an ``__init__.py`` file. Even if empty, this marks a
directory as a Python package.
Configuration With ``configure.zcml``
--------------------------------------
The ``bfg_zodb`` template uses :term:`ZCML` to perform system
configuration. The ZCML file generated by the template looks like the
following:
.. literalinclude:: src/basiclayout/tutorial/configure.zcml
:linenos:
:language: xml
#. *Line 1*. The root ``<configure>`` element, in a ``bfg``
namespace.
#. *Line 4*. Boilerplate, the comment explains.
#. *Lines 6-10*. Register a ``<view>`` that is ``for`` a class.
``.views.my_view`` is a *function* we write (generated by the
``bfg_zodb`` template) that is given a ``context`` and a
``request`` and which returns a dictionary. The ``renderer`` tag
indicates that the ``templates/mytemplate.pt`` template should be
used to turn the dictionary returned by the view into a response.
``templates/mytemplate.pt`` is a *relative* path: it names the
``mytemplate.pt`` file which lives in the ``templates``
subdirectory of the directory in which this ``configure.zcml``
lives in. In this case, it means it lives in the ``tutorial``
package's ``templates`` directory as ``mytemplate.pt``
Since this ``<view>`` doesn't have a ``name`` attribute, it is the
"default" view for that class.
#. *Lines 12-15*. Register a ``static`` view which answers requests
which start with ``/static``. This is a view that will serve up
static resources for us, in this case, at
``http://localhost:6543/static/`` and below. The ``path`` element
of this tag is a relative directory name, so it finds the resources
it should serve within the ``templates/static`` directory inside
the ``tutorial`` package.
Content Models with ``models.py``
---------------------------------
:mod:`repoze.bfg` often uses the word :term:`model` when talking about
content resources arranged in the hierarchical *object graph*
consulted by :term:`traversal`. The ``models.py`` file is where the
``bfg_zodb`` Paster template put the classes that implement our model
objects.
Here is the source for ``models.py``:
.. literalinclude:: src/basiclayout/tutorial/models.py
:linenos:
:language: py
#. *Lines 3-4*. The ``MyModel`` class we referred to in the ZCML file
named ``configure.zcml`` is implemented here. Instances of this
class will be capable of being persisted in :term:`ZODB` because
the class inherits from the
:class:`persistint.mapping.PersistentMapping` class. The
``__parent__`` and ``__name__`` are important parts of the
:term:`traversal` protocol. By default, have these as ``None``
indicating that this is the :term:`root` object.
#. *Lines 6-12*. ``appmaker`` is used to return the *application
root* object. It is called on *every request* to the
:mod:`repoze.bfg` application. It also performs bootstrapping by
*creating* an application root (inside the ZODB root object) if one
does not already exist.
We do so by first seeing if the database has the persistent
application root. If not, we make an instance, store it, and
commit the transaction. We then return the application root
object.
App Startup with ``run.py``
---------------------------
When you run the application using the ``paster`` command using the
``tutorial.ini`` generated config file, the application configuration
points at an Setuptools *entry point* described as
``egg:tutorial#app``. In our application, because the application's
``setup.py`` file says so, this entry point happens to be the ``app``
function within the file named ``run.py``:
.. literalinclude:: src/basiclayout/tutorial/run.py
:linenos:
:language: py
#. *Lines 1-3*. Perform some dependency imports.
#. *Line 11*. Get the ZODB configuration from the ``tutorial.ini``
file's ``[app:main]`` section represented by the ``settings``
dictionary passed to our ``app`` function. This will be a URI
(something like ``file:///path/to/Data.fs``).
#. *Line 14*. We create a "finder" object using the
:class:`repoze.zodbconn.finder.PersistentApplicationFinder` helper
class, passing it the ZODB URI and the "appmaker" we've imported
from ``models.py``.
#. *Lines 15 - 16*. We create a :term:`root factory` which uses the
finder to return a ZODB root object.
#. *Line 17*. We construct a :term:`Configurator` with a :term:`root
factory` and the settings keywords parsed by PasteDeploy. The root
factory is named ``get_root``.
#. *Lines 18-20*. Begin configuration using the
:meth:`repoze.bfg.configuration.Configurator.begin` method, load
the ``configure.zcml`` file from our package using the
:meth:`repoze.bfg.configuration.Configurator.load_zcml` method, and
end configuration using the
:meth:`repoze.bfg.configuration.Configurator.end` method.
#. *Line 21*. Use the
:meth:`repoze.bfg.configuration.Configurator.make_wsgi_app` method
to return a :term:`WSGI` application.
|