============ Basic Layout ============ The starter files generated by the ``zodb`` scaffold are basic, but they provide a good orientation for the high-level patterns common to most :term:`traversal` -based :app:`Pyramid` (and :term:`ZODB` based) projects. The source code for this tutorial stage can be browsed via `http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki/src/basiclayout/ `_. Application Configuration with ``__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. Our application uses ``__init__.py`` as both a package marker, as well as to contain application configuration code. When you run the application using the ``pserve`` command using the ``development.ini`` generated config file, the application configuration points at a Setuptools *entry point* described as ``egg:tutorial``. In our application, because the application's ``setup.py`` file says so, this entry point happens to be the ``main`` function within the file named ``__init__.py``: .. literalinclude:: src/basiclayout/tutorial/__init__.py :linenos: :language: py #. *Lines 1-3*. Perform some dependency imports. #. *Lines 5-7* Define a root factory for our Pyramid application. #. *Line 12*. We construct a :term:`Configurator` with a :term:`root factory` and the settings keywords parsed by :term:`PasteDeploy`. The root factory is named ``root_factory``. #. *Line 13*. Register a 'static view' which answers requests which start with with URL path ``/static`` using the :meth:`pyramid.config.Configurator.add_static_view method`. This statement registers a view that will serve up static assets, such as CSS and image files, for us, in this case, at ``http://localhost:6543/static/`` and below. The first argument is the "name" ``static``, which indicates that the URL path prefix of the view will be ``/static``. the The second argument of this tag is the "path", which is a relative :term:`asset specification`, so it finds the resources it should serve within the ``static`` directory inside the ``tutorial`` package. The scaffold could have alternately used an *absolute* asset specification as the path (``tutorial:static``) but it does not. #. *Line 14*. Perform a :term:`scan`. A scan will find :term:`configuration decoration`, such as view configuration decorators (e.g. ``@view_config``) in the source code of the ``tutorial`` package and will take actions based on these decorators. We don't pass any arguments to :meth:`~pyramid.config.Configurator.scan`, which implies that the scan should take place in the current package (in this case, ``tutorial``). The scaffold could have equivalently said ``config.scan('tutorial')`` but it chose to omit the package name argument. #. *Line 15*. Use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application. Resources and Models with ``models.py`` --------------------------------------- :app:`Pyramid` uses the word :term:`resource` to describe objects arranged hierarchically in a :term:`resource tree`. This tree is consulted by :term:`traversal` to map URLs to code. In this application, the resource tree represents the site structure, but it *also* represents the :term:`domain model` of the application, because each resource is a node stored persistently in a :term:`ZODB` database. The ``models.py`` file is where the ``zodb`` scaffold put the classes that implement our resource objects, each of which happens also to be a domain model object. Here is the source for ``models.py``: .. literalinclude:: src/basiclayout/tutorial/models.py :linenos: :language: py #. *Lines 3-4*. The ``MyModel`` :term:`resource` class is implemented here. Instances of this class will be capable of being persisted in :term:`ZODB` because the class inherits from the :class:`persistent.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 :app:`Pyramid` application. It also performs bootstrapping by *creating* an application root (inside the ZODB root object) if one does not already exist. It is used by the "root_factory" we've defined in our ``__init__.py``. 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. Views With ``views.py`` ----------------------- Our scaffold generated a default ``views.py`` on our behalf. It contains a single view, which is used to render the page shown when you visit the URL ``http://localhost:6543/``. Here is the source for ``views.py``: .. literalinclude:: src/basiclayout/tutorial/views.py :linenos: :language: py Let's try to understand the components in this module: #. *Lines 1-2*. Perform some dependency imports. #. *Line 4*. Use the :func:`pyramid.view.view_config` :term:`configuration decoration` to perform a :term:`view configuration` registration. This view configuration registration will be activated when the application is started. It will be activated by virtue of it being found as the result of a :term:`scan` (when Line 14 of ``__init__.py`` is run). The ``@view_config`` decorator accepts a number of keyword arguments. We use two keyword arguments here: ``context`` and ``renderer``. The ``context`` argument signifies that the decorated view callable should only be run when :term:`traversal` finds the ``tutorial.models.MyModel`` :term:`resource` to be the :term:`context` of a request. In English, this means that when the URL ``/`` is visited, because ``MyModel`` is the root model, this view callable will be invoked. The ``renderer`` argument names an :term:`asset specification` of ``templates/mytemplate.pt``. This asset specification points at a :term:`Chameleon` template which lives in the ``mytemplate.pt`` file within the ``templates`` directory of the ``tutorial`` package. And indeed if you look in the ``templates`` directory of this package, you'll see a ``mytemplate.pt`` template file, which renders the default home page of the generated project. This asset specification is *relative* (to the view.py's current package). We could have alternately an used the absolute asset specification ``tutorial:templates/mytemplate.pt``, but chose to use the relative version. Since this call to ``@view_config`` doesn't pass a ``name`` argument, the ``my_view`` function which it decorates represents the "default" view callable used when the context is of the type ``MyModel``. #. *Lines 5-6*. We define a :term:`view callable` named ``my_view``, which we decorated in the step above. This view callable is a *function* we write generated by the ``zodb`` scaffold that is given a ``request`` and which returns a dictionary. The ``mytemplate.pt`` :term:`renderer` named by the asset specification in the step above will convert this dictionary to a :term:`response` on our behalf. The function returns the dictionary ``{'project':'tutorial'}``. This dictionary is used by the template named by the ``mytemplate.pt`` asset specification to fill in certain values on the page. Configuration in ``development.ini`` ------------------------------------ The ``development.ini`` (in the tutorial :term:`project` directory, as opposed to the tutorial :term:`package` directory) looks like this: .. literalinclude:: src/views/development.ini :language: ini Note the existence of an ``[app:main]`` section which specifies our WSGI application. Our ZODB database settings are specified as the ``zodbconn.uri`` setting within this section. This value, and the other values within this section are passed as ``**settings`` to the ``main`` function we defined in ``__init__.py`` when the server is started via ``pserve``.