summaryrefslogtreecommitdiff
path: root/docs/tutorials/wiki/basiclayout.rst
diff options
context:
space:
mode:
authorSteve Piercy <web@stevepiercy.com>2018-11-26 23:59:40 -0800
committerSteve Piercy <web@stevepiercy.com>2018-11-26 23:59:40 -0800
commit2615104ce4ba383a46df3c27ba26cfb86654e116 (patch)
treead938e23efd1be67821ddfb710748e746c92c420 /docs/tutorials/wiki/basiclayout.rst
parent28f24e7592fc5a7fd28874e9a350f80674583471 (diff)
parent587fe72fae0efda3a860d37a1ea2449a41dab622 (diff)
downloadpyramid-2615104ce4ba383a46df3c27ba26cfb86654e116.tar.gz
pyramid-2615104ce4ba383a46df3c27ba26cfb86654e116.tar.bz2
pyramid-2615104ce4ba383a46df3c27ba26cfb86654e116.zip
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'docs/tutorials/wiki/basiclayout.rst')
-rw-r--r--docs/tutorials/wiki/basiclayout.rst355
1 files changed, 211 insertions, 144 deletions
diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst
index 49ee6902e..52d3f4670 100644
--- a/docs/tutorials/wiki/basiclayout.rst
+++ b/docs/tutorials/wiki/basiclayout.rst
@@ -4,188 +4,255 @@
Basic Layout
============
-The starter files generated by selecting the ``zodb`` backend in the
-cookiecutter are very basic, but they provide a good orientation for the
-high-level patterns common to most :term:`traversal`-based (and
-:term:`ZODB`-based) :app:`Pyramid` projects.
+The starter files generated by the cookiecutter are very basic, but they provide a good orientation for the high-level patterns common to most :term:`traversal`-based (and :term:`ZODB`-based) :app:`Pyramid` projects.
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 in
-which it's contained is a package, and to contain application configuration
-code.
+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 in which it is contained is a package, and to contain application configuration code.
-When you run the application using the ``pserve`` command using the
-``development.ini`` generated configuration file, the application
-configuration points at a :term:`Setuptools` :term:`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``.
+When you run the application using the ``pserve`` command using the ``development.ini`` generated configuration file, the application configuration points at a :term:`Setuptools` :term:`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``.
-Open ``tutorial/__init__.py``. It should already contain the following:
+Open ``tutorial/__init__.py``.
+It should already contain the following:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :linenos:
- :language: 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: root_factory
+ :lineno-match:
+ :language: py
+
+Define a :term:`root factory` for our Pyramid application.
+It establishes a connection to ZODB database.
+It returns an ``appmaker``, which we will describe in the next section :ref:`wiki-resources-and-models`.
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :pyobject: root_factory
+ :lineno-match:
+ :language: py
+
+``__init__.py`` defines a function named ``main``.
+Here is the entirety of the ``main`` function that we have defined in our ``__init__.py``:
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :pyobject: main
+ :lineno-match:
+ :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``.
+
+Next in ``main``, construct a :term:`Configurator` object using a context manager.
+See also :term:`Deployment settings`.
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 14
+ :lineno-match:
+ :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``, ``zodbconn.uri``, and so on.
+
+Next include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.org/project/transaction/>`_ package.
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 15
+ :lineno-match:
+ :language: py
+
+Next include support for ``pyramid_retry`` to retry a request when transient exceptions occur.
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 16
+ :lineno-match:
+ :language: py
+
+Next include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application.
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 17
+ :lineno-match:
+ :language: py
+
+Next set a root factory using our function named ``root_factory``.
+
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 18
+ :lineno-match:
+ :language: py
+
+Next include support for the :term:`Chameleon` template rendering bindings, allowing us to use the ``.pt`` templates.
-#. *Lines 1-3*. Perform some dependency imports.
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 19
+ :lineno-match:
+ :language: py
-#. *Lines 6-8*. Define a :term:`root factory` for our Pyramid application.
+Next include routes from the ``.routes`` module.
-#. *Line 11*. ``__init__.py`` defines a function named ``main``.
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 20
+ :lineno-match:
+ :language: py
-#. *Line 14*. Use an explicit transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle.
+This registers a "static view" using the :meth:`pyramid.config.Configurator.add_static_view` method.
+This view answers requests whose URL path starts with ``/static``.
+This statement registers a view that will serve up static assets, such as CSS and image files.
+In this case the URL will answer requests at ``http://localhost:6543/static/`` and below.
-#. *Line 15*. Construct a :term:`Configurator` as a :term:`context manager` with the settings keyword parsed by :term:`PasteDeploy`.
+The first argument is the "name" ``static``, which indicates that the URL path prefix of the view will be ``/static``.
-#. *Line 16*. Include support for the :term:`Chameleon` template rendering
- bindings, allowing us to use the ``.pt`` templates.
+The second argument of this method is the "path".
+It is a relative :term:`asset specification`.
+It finds the resources it should serve within the ``static`` directory inside the ``tutorial`` package.
+Alternatively the cookiecutter could have used an *absolute* asset specification as the path (``tutorial:static``).
-#. *Line 17*. Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.org/project/transaction/>`_ package.
+The third argument is an optional ``cache_max_age`` which specifies the number of seconds the static asset will be HTTP-cached.
-#. *Line 18*. Include support for ``pyramid_retry`` to retry a request when transient exceptions occur.
+Next perform a :term:`scan`.
-#. *Line 19*. Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application.
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 21
+ :lineno-match:
+ :language: py
-#. *Line 20*. Set a root factory using our function named ``root_factory``.
+A scan will find :term:`configuration decoration`, such as view configuration decorators (e.g., ``@view_config``) in the source code of the ``tutorial`` package.
+It 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 cookiecutter could have equivalently said ``config.scan('tutorial')``, but it chose to omit the package name argument.
-#. *Line 21*. Register a "static view", which answers requests whose URL
- paths start with ``/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 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. Alternatively the cookiecutter could have used an *absolute* asset
- specification as the path (``tutorial:static``).
+Finally use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application.
-#. *Line 22*. 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 cookiecutter could have equivalently said ``config.scan('tutorial')``, but
- it chose to omit the package name argument.
+.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 22
+ :lineno-match:
+ :language: py
-#. *Line 23*. Use the
- :meth:`pyramid.config.Configurator.make_wsgi_app` method
- to return a :term:`WSGI` application.
-Resources and models with ``models.py``
----------------------------------------
+.. _wiki-resources-and-models:
-: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`` cookiecutter put the classes that implement our
-resource objects, each of which also happens to be a domain model object.
+Resources and models with ``models`` package
+--------------------------------------------
+
+: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.
+Each resource is a node stored persistently in a :term:`ZODB` database.
+The ``models.py`` file is where the ``zodb`` cookiecutter put the classes that implement our resource objects, each of which also happens to be a domain model object.
Here is the source for ``models.py``:
-.. literalinclude:: src/basiclayout/tutorial/models.py
+.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
:linenos:
:language: python
-#. *Lines 4-5*. The ``MyModel`` :term:`resource` class is implemented here.
- Instances of this class are 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, set these to ``None`` to indicate that this is the
- :term:`root` object.
-
-#. *Lines 8-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``.
-
- Bootstrapping is done 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 cookiecutter 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: python
+#. *Lines 4-5*.
+ The ``MyModel`` :term:`resource` class is implemented here.
+ Instances of this class are 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, these are set to ``None`` to indicate that this is the :term:`root` object.
+
+#. *Lines 8-12*.
+ ``appmaker`` is used to return the *application root* object.
+ It is called on *every request* to the :app:`Pyramid` application by virtue of the ``root_factory`` defined in our ``__init__.py``.
+ It also performs bootstrapping by *creating* an application root (inside the ZODB root object) if one does not already exist.
+
+ Bootstrapping is done by first seeing if the database has the persistent application root.
+ If not, then we make an instance, store it, and commit the transaction.
+
+ We then return the application root object.
+
+
+View declarations via the ``views`` package
+-------------------------------------------
+
+Our cookiecutter generated a default ``views`` package on our behalf.
+It contains a two views.
+
+The first view is used to render the page shown when you visit the URL ``http://localhost:6543/``.
+Open ``tutorial/views/default.py`` in the ``views`` package.
+It should already contain the following:
+
+.. literalinclude:: src/basiclayout/tutorial/views/default.py
+ :linenos:
+ :language: python
Let's try to understand the components in this module:
-#. *Lines 1-2*. Perform some dependency imports.
-
-#. *Line 5*. 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). Alternatively we could have 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 6-7*. 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`` cookiecutter 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.
+#. *Lines 1-3*.
+ Perform some dependency imports.
+
+#. *Line 6*.
+ 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.
+ Remember in our application's ``__init__.py`` when we executed the :meth:`pyramid.config.Configurator.scan` method ``config.scan()``?
+ By calling the scan method, Pyramid's configurator will find and process this ``@view_config`` decorator, and 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`.
+
+ 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 ``my_view`` should only be run when :term:`traversal` finds the ``tutorial.models.MyModel`` :term:`resource` as the :term:`context` of a request.
+ In English this means that when the URL ``/`` is visited, and 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 will see a ``mytemplate.pt`` template file
+ This template renders the default home page of the generated project.
+ This asset specification is *relative* to the ``views`` package.
+ Alternatively we could have used the absolute asset specification ``tutorial:templates/mytemplate.pt``.
+
+ 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 7-8*.
+ A :term:`view callable` named ``my_view`` is defined, which is decorated in the step above.
+ This view callable is a *function* generated by the cookiecutter.
+ It is given a single argument, ``request``.
+ This is the standard call signature for a Pyramid :term:`view callable`.
+ The function returns the dictionary ``{'project': 'myproj'}``.
+ This dictionary is used by the template named by the ``mytemplate.pt`` asset specification to fill in certain values on the page.
+
+Let us open ``tutorial/views/default.py`` in the ``views`` package to look at the second view.
+
+.. literalinclude:: src/basiclayout/tutorial/views/notfound.py
+ :linenos:
+ :language: python
+
+Without repeating ourselves, we will point out the differences between this view and the previous.
+
+#. *Line 4*.
+ The ``notfound_view`` function is decorated with ``@notfound_view_config``.
+ This decorator registers a :term:`Not Found View` using :meth:`pyramid.config.Configurator.add_notfound_view`.
+
+ The ``renderer`` argument names an :term:`asset specification` of ``templates/404.pt``.
+
+#. *Lines 5-7*.
+ A :term:`view callable` named ``notfound_view`` is defined, which is decorated in the step above.
+ It sets the HTTP response status code to ``404``.
+ The function returns an empty dictionary to the template ``404.pt``, which accepts no parameters anyway.
+
Configuration in ``development.ini``
------------------------------------
-The ``development.ini`` (in the ``tutorial`` :term:`project` directory, as
-opposed to the ``tutorial`` :term:`package` directory) looks like this:
+The ``development.ini`` (in the ``tutorial`` :term:`project` directory, as opposed to the ``tutorial`` :term:`package` directory) looks like this:
.. literalinclude:: src/basiclayout/development.ini
:language: ini
-Note the existence of a ``[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``.
+Note the existence of a ``[app:main]`` section which specifies our WSGI application.
+Our ZODB database settings are specified as the ``zodbconn.uri`` setting within this section.
+When the server is started via ``pserve``, the values within this section are passed as ``**settings`` to the ``main`` function defined in ``__init__.py``.