============ Basic Layout ============ The starter files generated by the ``alchemy`` scaffold are very basic, but they provide a good orientation for the high-level patterns common to most :term:`url dispatch` -based :app:`Pyramid` projects. The source code for this tutorial stage can be browsed at `http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki2/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. We use ``__init__.py`` both as a marker indicating the directory it's contained within is a package, and to contain configuration code. Open ``tutorial/tutorial/__init__.py``. It should already contain the following: .. literalinclude:: src/basiclayout/tutorial/__init__.py :linenos: :language: py Let's go over this piece-by-piece. First, we need some imports to support later code: .. literalinclude:: src/basiclayout/tutorial/__init__.py :end-before: main :linenos: :language: py ``__init__.py`` defines a function named ``main``. Here is the entirety of the ``main`` function we've defined in our ``__init__.py``: .. literalinclude:: src/basiclayout/tutorial/__init__.py :pyobject: main :linenos: :language: py When you invoke the ``pserve development.ini`` command, the ``main`` function above is executed. It accepts some settings and returns a :term:`WSGI` application. (See :ref:`startup_chapter` for more about ``pserve``.) The main function first creates a SQLAlchemy database engine using ``engine_from_config`` from the ``sqlalchemy.`` prefixed settings in the ``development.ini`` file's ``[app:main]`` section. This will be a URI (something like ``sqlite://``): .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 9 :linenos: :language: py ``main`` then initializes our SQL database using SQLAlchemy, passing it the engine: .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 10 :language: py The next step of ``main`` is to construct a :term:`Configurator` object: .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 11 :language: py ``settings`` is passed to the Configurator as a keyword argument with the dictionary values passed as the ``**settings`` argument. This will be a dictionary of settings parsed from the ``.ini`` file, which contains deployment-related values such as ``pyramid.reload_templates``, ``db_string``, etc. ``main`` now calls :meth:`pyramid.config.Configurator.add_static_view` with two arguments: ``static`` (the name), and ``static`` (the path): .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 12 :language: py This registers a static resource view which will match any URL that starts with the prefix ``/static`` (by virtue of the first argument to add_static view). This will serve up static resources for us from within the ``static`` directory of our ``tutorial`` package, in this case, via ``http://localhost:6543/static/`` and below (by virtue of the second argument to add_static_view). With this declaration, we're saying that any URL that starts with ``/static`` should go to the static view; any remainder of its path (e.g. the ``/foo`` in ``/static/foo``) will be used to compose a path to a static file resource, such as a CSS file. Using the configurator ``main`` also registers a :term:`route configuration` via the :meth:`pyramid.config.Configurator.add_route` method that will be used when the URL is ``/``: .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 13 :language: py Since this route has a ``pattern`` equalling ``/`` it is the route that will be matched when the URL ``/`` is visited, e.g. ``http://localhost:6543/``. ``main`` next calls the ``scan`` method of the configurator, which will recursively scan our ``tutorial`` package, looking for ``@view_config`` (and other special) decorators. When it finds a ``@view_config`` decorator, a view configuration will be registered, which will allow one of our application URLs to be mapped to some code. .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 14 :language: py Finally, ``main`` is finished configuring things, so it uses the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application: .. literalinclude:: src/basiclayout/tutorial/__init__.py :lines: 15 :language: py View Declarations via ``views.py`` ---------------------------------- Mapping a :term:`route` to code that will be executed when a match for the route's pattern occurs is done by registering a :term:`view configuration`. Our application uses the :meth:`pyramid.view.view_config` decorator to map view callables to each route, thereby mapping URL patterns to code. Open ``tutorial/tutorial/views.py``. It should already contain the following: .. literalinclude:: src/basiclayout/tutorial/views.py :linenos: :language: py The important part here is that the ``@view_config`` decorator associates the function it decorates (``my_view``) with a :term:`view configuration`, consisting of: * a ``route_name`` (``home``) * a ``renderer``, which is a template from the ``templates`` subdirectory of the package. When the pattern associated with the ``home`` view is matched during a request, ``my_view()`` will be executed. ``my_view()`` returns a dictionary; the renderer will use the ``templates/mytemplate.pt`` template to create a response based on the values in the dictionary. Note that ``my_view()`` accepts a single argument named ``request``. This is the standard call signature for a Pyramid :term:`view callable`. Remember in our ``__init__.py`` when we executed the :meth:`pyramid.config.Configurator.scan` method, i.e. ``config.scan()``? The purpose of calling the scan method was to find and process this ``@view_config`` decorator in order to create a view configuration within our application. Without being processed by ``scan``, the decorator effectively does nothing. ``@view_config`` is inert without being detected via a :term:`scan`. Content Models with ``models.py`` --------------------------------- In a SQLAlchemy-based application, a *model* object is an object composed by querying the SQL database. The ``models.py`` file is where the ``alchemy`` scaffold put the classes that implement our models. Open ``tutorial/tutorial/models.py``. It should already contain the following: .. literalinclude:: src/basiclayout/tutorial/models.py :linenos: :language: py Let's examine this in detail. First, we need some imports to support later code: .. literalinclude:: src/basiclayout/tutorial/models.py :end-before: DBSession :linenos: :language: py Next we set up a SQLAlchemy "DBSession" object: .. literalinclude:: src/basiclayout/tutorial/models.py :lines: 16 :linenos: :language: py ``scoped_session`` and ``sessionmaker`` are standard SQLAlchemy helpers. ``scoped_session`` allows us to access our database connection globally. ``sessionmaker`` creates a database session object. We pass to ``sessionmaker`` the ``extension=ZopeTransactionExtension()`` extension option in order to allow the system to automatically manage database transactions. With ``ZopeTransactionExtension`` activated, our application will automatically issue a transaction commit after every request unless an exception is raised, in which case the transaction will be aborted. We also need to create a declarative ``Base`` object to use as a base class for our model: .. literalinclude:: src/basiclayout/tutorial/models.py :lines: 17 :language: py Our model classes will inherit from this ``Base`` class so they can be associated with our particular database connection. To give a simple example of a model class, we define one named ``MyModel``: .. literalinclude:: src/basiclayout/tutorial/models.py :pyobject: MyModel :linenos: :language: py Our example model has an ``__init__`` that takes a two arguments (``name``, and ``value``). It stores these values as ``self.name`` and ``self.value`` within the ``__init__`` function itself. The ``MyModel`` class also has a ``__tablename__`` attribute. This informs SQLAlchemy which table to use to store the data representing instances of this class. That's about all there is to it to models, views, and initialization code in our stock application.