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 traversal -based repoze.bfg (and ZODB based) projects.
A directory on disk can be turned into a Python package by containing an __init__.py file. Even if empty, this marks a directory as a Python package.
repoze.bfg uses a markup language syntactically the same as Zope’s implementation of ZCML, but using a different default XML namespace. Our sample ZCML file looks like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <configure xmlns="http://namespaces.repoze.org/bfg"> <!-- this must be included for the view declarations to work --> <include package="repoze.bfg.includes" /> <view for=".models.MyModel" view=".views.my_view" /> <view for=".models.MyModel" view=".views.static_view" name="static" /> </configure>
Line 1. The root <configure> element, in a bfg namespace.
Line 4. 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.
repoze.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:
1 2 3 4 5 6 7 8 9 10 11 12 from persistent.mapping import PersistentMapping class MyModel(PersistentMapping): __parent__ = __name__ = None def appmaker(zodb_root): if not 'app_root' in zodb_root: app_root = MyModel() zodb_root['app_root'] = app_root import transaction transaction.commit() return zodb_root['app_root']
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 root object.
Lines 6-12. appmaker is used to return the application root object. It is called on every request to the 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.
How does a 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from repoze.bfg.router import make_app from repoze.zodbconn.finder import PersistentApplicationFinder def app(global_config, **kw): """ This function returns a repoze.bfg.router.Router object. It is usually called by the PasteDeploy framework during ``paster serve``. """ # paster app config callback import tutorial from tutorial.models import appmaker zodb_uri = kw.get('zodb_uri') if zodb_uri is None: raise ValueError("No 'zodb_uri' in application configuration.") get_root = PersistentApplicationFinder(zodb_uri, appmaker) return make_app(get_root, tutorial, options=kw)