============ 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/master/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. Our ``__init__.py`` file will look like this: .. 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. You can read :ref:`startup_chapter` for details about *how* this function is found and called when you run ``pserve``, but for purposes of brevity, we'll elide the details here. 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 visted, 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 that route's pattern matches 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. Here is the code in the ``views.py`` file within our package: .. literalinclude:: src/basiclayout/tutorial/views.py :linenos: :language: py The important part to point out here is the ``@view_config`` decorator. In fact, ``@view_config`` is so important that we're going to ignore the rest of the code in the module at this point just to explain it. The ``@view_config`` decorator associates the function it decorates with a :term:`view configuration`. The view configuration names a ``route_name`` (``home``), and names a ``renderer``, which is a template which lives in the ``templates`` subdirectory of the package. As the result of this view configuration, when the pattern associated with the view named ``home`` is matched during a request, the function named ``my_view`` will be executed. The the function named ``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 the decorated function named ``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, e.g. ``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. SQLAlchemy is an "object relational mapper" (an ORM). The ``models.py`` file is where the ``alchemy`` scaffold put the classes that implement our models. Let's take a look. 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: 15-16 :linenos: :language: py 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 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 sample 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. Next we define a function named ``populate`` which adds a single model instance into our SQL storage and commits a transaction: .. literalinclude:: src/basiclayout/tutorial/models.py :pyobject: populate :linenos: :language: py The function doesn't do a lot in this case, but it's there to illustrate how an application requiring many objects to be set up could work. Lastly we have a function named ``initialize_sql`` which receives a SQL database engine and binds it to our SQLAlchemy DBSession object. It also calls the ``populate`` function, to do initial database population. This is the initialization function that is called from __init__.py above. .. literalinclude:: src/basiclayout/tutorial/models.py :pyobject: initialize_sql :linenos: :language: py Here is the complete source for ``models.py``: .. literalinclude:: src/basiclayout/tutorial/models.py :linenos: :language: py