summaryrefslogtreecommitdiff
path: root/docs/tutorials/bfgwiki/basiclayout.rst
blob: d373624dec3adc241d8f812b342665edac94e3a5 (plain)
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
============
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``
--------------------------------------

:mod:`repoze.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 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 *model* when talking about
content resources arranged in a hierarchical *object 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
   :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``
---------------------------

How does a :mod:`repoze.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 "finder" object using the
   ``PersistentApplicationFinder`` helper class, passing it the ZODB
   URI and our appmaker.

#. *Lines 17 - 18*.  We create a :term:`root factory` using the finder.

#. Line *19*.  We construct a :term:`Configurator` with a
   :term:`root factory` and the settings keywords parsed by
   PasteDeploy.  The root factory is named ``get_root``.  We then use
   the ``make_wsgi_app`` method of the :term:`Configurator` to return
   a :term:`WSGI` application.