diff options
Diffstat (limited to 'docs/tutorials/wiki2/basiclayout.rst')
| -rw-r--r-- | docs/tutorials/wiki2/basiclayout.rst | 159 |
1 files changed, 100 insertions, 59 deletions
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst index db8ab1fbe..dc5664c5b 100644 --- a/docs/tutorials/wiki2/basiclayout.rst +++ b/docs/tutorials/wiki2/basiclayout.rst @@ -2,82 +2,96 @@ Basic Layout ============ -The starter files generated by the ``alchemy`` scaffold are -basic, but they provide a good orientation for the high-level patterns common -to most :term:`url dispatch` -based :app:`Pyramid` projects. +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/ <http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/basiclayout/>`_. -App Startup with ``__init__.py`` --------------------------------- +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 package marker and to contain -configuration code. +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: -The generated ``development.ini`` file is read by ``pserve`` which looks for -the application module in the ``use`` variable of the ``app:main`` -section. The *entry point* is defined in the Setuptools configuration of this -module, specifically in the ``setup.py`` file. For this tutorial, the *entry -point* is defined as ``tutorial:main`` and points to a function named -``main``. + .. literalinclude:: src/basiclayout/tutorial/__init__.py + :linenos: + :language: py -First we need some imports to support later code: +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 -Next we define the main function and create a SQLAlchemy database engine from -the ``sqlalchemy.`` prefixed settings in the ``development.ini`` file's -``[app:main]`` section. This will be a URI (something like -``sqlite://``): +``__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: 6-9 + :lines: 9 :linenos: :language: py -We then initialize our SQL database using SQLAlchemy, passing -it the engine: +``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 is to construct a :term:`Configurator`: +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 by PasteDeploy 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``, +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. -We now can call :meth:`pyramid.config.Configurator.add_static_view` with the -arguments ``static`` (the name), and ``tutorial:static`` (the path): +``'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 -``/static/``. 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. 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. +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 we can also register a :term:`route configuration` +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 ``/``: @@ -88,44 +102,71 @@ used when the URL is ``/``: 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/``. -Mapping the ``home`` route to code is done by registering a view. You will -use :meth:`pyramid.config.Configurator.add_view` in :term:`URL dispatch` to -register views for the routes, mapping your patterns to code: +``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-15 + :lines: 14 :language: py -The first positional ``add_view`` argument ``tutorial.views.my_view`` is the -dotted name to a *function* we write (generated by the -``alchemy`` scaffold) that is given a ``request`` object and -which returns a response or a dictionary. This view also names a -``renderer``, which is a template which lives in the ``templates`` -subdirectory of the package. When the ``tutorial.views.my_view`` view -returns a dictionary, a :term:`renderer` will use this template to create a -response. - -Finally, we use the :meth:`pyramid.config.Configurator.make_wsgi_app` -method to return a :term:`WSGI` application: +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: 16 + :lines: 15 :language: py -Our final ``__init__.py`` file will look like this: +View Declarations via ``views.py`` +---------------------------------- - .. literalinclude:: src/basiclayout/tutorial/__init__.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 which backs an application. -SQLAlchemy is an "object relational mapper" (an ORM). The -``models.py`` file is where the ``alchemy`` scaffold -put the classes that implement our models. +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. |
