From 6117c04a79d29b710391d95c5cce63358c5490fe Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 1 Jun 2009 00:15:14 +0000 Subject: Keep useful stuff. --- docs/tutorials/bfgwiki2/basiclayout.rst | 129 +++++++++++++++++++------------- 1 file changed, 79 insertions(+), 50 deletions(-) (limited to 'docs/tutorials/bfgwiki2/basiclayout.rst') diff --git a/docs/tutorials/bfgwiki2/basiclayout.rst b/docs/tutorials/bfgwiki2/basiclayout.rst index 1ec10094e..7cf8274c8 100644 --- a/docs/tutorials/bfgwiki2/basiclayout.rst +++ b/docs/tutorials/bfgwiki2/basiclayout.rst @@ -2,9 +2,9 @@ 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. +The starter files generated by the ``bfg_routesalchemy`` template are +basic, but they provide a good orientation for the high-level patterns +common to most :term:`url dispatch` -based BFG projects. ``__init__.py`` --------------- @@ -16,9 +16,9 @@ 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: +BFG uses a configuration 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: @@ -28,26 +28,29 @@ namespace. Our sample ZCML file looks like the following: #. *Line 3*. Boilerplate, the comment explains. -#. *Lines 6-9*. Register a ```` 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. +#. *Lines 6-7*. Register a :term:`subscriber` that tears down the + SQLAlchemy connection after a request is finished. - Since this ```` doesn't have a ``name`` attribute, it is the - "default" view for that class. +#. *Lines 9-12*. Register a ```` that will be used when the + URL is ``/``. Since this ```` has a blank ``name`` + attribute, it is the "default" view. ``.views.my_view`` refers to a + *function* we write (generated by the ``bfg_routesalchemy`` + template) that is given a ``context`` and a ``request`` and returns + a response. -#. *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 +#. *Lines 14-17*. Register a ```` with a path that starts with + ``/static``, capturing the rest of the URL as ``subpath``. 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. +In the context of a SQLAlchemy-based application, a *model* object is +an object composed by quering the SQL database which backs an +application. SQLAlchemy is an "object relational mapper" (an ORM). +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``: @@ -55,22 +58,36 @@ Here is the source for ``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. +#. *Lines 1-16*. Imports to support later code. + +#. *Line 18*. We set up a SQLAlchemy "DBSession" object here. We + specify that we'd like to use the "ZopeTransactionExtension". This + extension is an extension which allows us to use a *transaction + manager* instead of controlling commits and aborts to database + operations by hand. + +#. *Line 20*. Set up a SQLAlchemy metadata object. + +#. *Lines 22-24*. A model class named ``Model``. It has an + ``__init__`` that takes a single argument (``name``). It stores a + single attribute named ``name``. + +#. *Lines 26-31*. A SQLAlchemy ``Table`` declaration named + ``models_table`` which we'll use later to map onto our ``Model`` + class. + +#. *Line 33*. We map our ``models_table`` table to our Models class + here. This makes an association between the ``Model`` class and + the ``models`` table in the database, as far as SQLAlchemy is + concerned. + +#. *Lines 35-40*. A function named ``populate`` which adds a single + model instance into our SQL storage and commits a transaction. + +#. *Lines 42-50*. A function named ``initialize_sql`` which sets up + an actual SQL database and binds it to our SQLAlchemy DBSession + object. It also calls the ``populate`` function, to do initial + database population. App Startup with ``run.py`` --------------------------- @@ -84,21 +101,33 @@ and its ``app`` function: :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. +#. *Lines 1-5*. Imports to support later code. + +#. *Lines 7-11*. We define a ``Cleanup`` class which has a + ``__del__`` method (the method called at Python object + destruction), which calls a function. + +#. *Lines 13-15*. An event :term:`subscriber` which adds a + ``Cleanup`` instance to the WSGI environment as + ``tutorial.sasession``. As a result of registering this event + subscriber, when the WSGI environment is cleaned up, our database + connection will be removed. + +#. *Lines 17-24*. Get the database configuration string from the + ``tutorial.ini`` file's ``[app:sql]`` section. This will be a URI + (something like ``sqlite://``). + +#. Line *25*. We initialize our SQL database using SQLAlchemy, passing + it the db string. + +#. Line *26*. We use the ``repoze.bfg.router.make_app`` to return a + :term:`WSGI` application. The ``make_app`` function's first + parameter is the "root factory". Since this is a URL dispatch + application, the root factory is ``None`` (we don't do any + :term:`traversal` in this app. The second argument is the + *package* representing our application, and the third argument, + ``options`` is passed as a keyword argument. It contains a + dictionary of options parsed by PasteDeploy. We'll later change ``run.py`` when we add :term:`authorization` to our wiki application. -- cgit v1.2.3