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
|
============
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 BFG (and BFG with ZODB) 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``
--------------------------------------
BFG uses a markup language syntactically the same as Zope's
implementation of :term:`ZCML`, but using a different default XML
namespace. Our sample ZCML file looks like the following:
.. literalinclude:: src/basiclayout/tutorial/configure.zcml
:linenos:
:language: xml
#. *Line 1*. The root ``<configure>`` element, in a *BFG* namespace.
#. *Line 3*. Boilerplate, the comment explains.
#. *Lines 6-9*. Register a ``<view>`` that is bound to 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 returns a response.
Since this ``<view>`` doesn't have a ``name`` attribute, it is the
"default" view for that class.
#. *Lines 11-15*. Register a view on the ``MyModels`` class that
answers URL segments of ``static``. This is a view that will serve
up static resources for us, in this case, at
``http://localhost:6543/static/`` and below.
Content Models with ``models.py``
---------------------------------
BFG often uses the word *model* when talking about content resources
arranged in a hierarchical *model graph*. The ``models.py`` file is
where the ``bfg_zodb`` Paster template put the classes that implement
our models.
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 is
implemented here. It is persistent (via PersistentMapping). The
``__parent__`` and ``__name__`` are important parts of the
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 BFG
application (it is essentially a :term:`root factory`). 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``
---------------------------
How does a BFG application start up? When you run under ``paster``
using the ``tutorial.ini`` generated config file, the application area
points at an entry point. Our entry point happens to be in ``run.py``
and its ``app`` function:
.. literalinclude:: src/basiclayout/tutorial/run.py
:linenos:
:language: py
#. *Line 11*. After importing our application, get the ``appmaker``
function described above.
#. *Line 12*. Get the ZODB configuration from the ``tutorial.ini``
file's ``[app:main]`` section. This will be a URI (something like
``file:///path/to/Data.fs``).
#. Line *16*. We create a :term:`root factory` using the
``PersistentApplicationFinder`` helper class, passing it the
ZODB URI and our appmaker.
#. Line *17*. We use the ``repoze.bfg.router.make_app`` to return a
:term:`WSGI` application. The ``make_app`` function takes the root
factory (``get_root``), the *package* representing our application,
and the keywords parsed by PasteDeploy.
We'll later change ``run.py`` when we add :term:`authorization` to our
wiki application.
|