summaryrefslogtreecommitdiff
path: root/docs/tutorials/wiki2/basiclayout.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/tutorials/wiki2/basiclayout.rst')
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst214
1 files changed, 123 insertions, 91 deletions
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 695d7f15b..e3d0a0a3c 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -12,12 +12,12 @@ 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
+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.
-Open ``tutorial/tutorial/__init__.py``. It should already contain
-the following:
+Open ``tutorial/tutorial/__init__.py``. It should already contain the
+following:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:linenos:
@@ -36,6 +36,7 @@ the ``main`` function we've defined in our ``__init__.py``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:pyobject: main
+ :lineno-start: 4
:linenos:
:language: py
@@ -43,58 +44,41 @@ 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 :term:`SQLAlchemy` database engine using
-:func:`sqlalchemy.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: 13
- :language: py
-
-``main`` then initializes our SQLAlchemy session object, passing it the
-engine:
+Next in ``main``, construct a :term:`Configurator` object:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 14
- :language: py
-
-``main`` subsequently initializes our SQLAlchemy declarative ``Base`` object,
-assigning the engine we created to the ``bind`` attribute of it's
-``metadata`` object. This allows table definitions done imperatively
-(instead of declaratively, via a class statement) to work. We won't use any
-such tables in our application, but if you add one later, long after you've
-forgotten about this tutorial, you won't be left scratching your head when it
-doesn't work.
-
- .. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 15
- :language: py
-
-The next step of ``main`` is to construct a :term:`Configurator` object:
-
- .. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 16
+ :lines: 7
+ :lineno-start: 7
: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.
+``sqlalchemy.url``, and so on.
+
+Next include :term:`Jinja2` templating bindings so that we can use renderers
+with the ``.jinja2`` extension within our project.
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 8
+ :lineno-start: 8
+ :language: py
-Next, include :term:`Chameleon` templating bindings so that we can use
-renderers with the ``.pt`` extension within our project.
+Next include the module ``meta`` from the package ``models`` using a dotted
+Python path.
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 17
+ :lines: 9
+ :lineno-start: 9
:language: py
``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: 18
+ :lines: 10
+ :lineno-start: 10
:language: py
This registers a static resource view which will match any URL that starts
@@ -112,11 +96,12 @@ via the :meth:`pyramid.config.Configurator.add_route` method that will be
used when the URL is ``/``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 19
+ :lines: 11
+ :lineno-start: 11
:language: py
-Since this route has a ``pattern`` equaling ``/`` it is the route that will
-be matched when the URL ``/`` is visited, e.g. ``http://localhost:6543/``.
+Since this route has a ``pattern`` equaling ``/``, 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
(:meth:`pyramid.config.Configurator.scan`), which will recursively scan our
@@ -126,28 +111,32 @@ 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: 20
+ :lines: 12
+ :lineno-start: 12
:language: py
-Finally, ``main`` is finished configuring things, so it uses the
+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: 21
+ :lines: 13
+ :lineno-start: 13
:language: py
-View declarations via ``views.py``
-----------------------------------
+
+View declarations via the ``views`` package
+-------------------------------------------
The main function of a web framework is mapping each URL pattern to code (a
:term:`view callable`) that is executed when the requested URL matches the
corresponding :term:`route`. Our application uses the
:meth:`pyramid.view.view_config` decorator to perform this mapping.
-Open ``tutorial/tutorial/views.py``. It should already contain the following:
+Open ``tutorial/tutorial/views/default.py`` in the ``views`` package. It
+should already contain the following:
- .. literalinclude:: src/basiclayout/tutorial/views.py
+ .. literalinclude:: src/basiclayout/tutorial/views/default.py
:linenos:
:language: py
@@ -156,13 +145,13 @@ 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.
+ * 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.
+``my_view()`` will be executed. ``my_view()`` returns a dictionary; the
+renderer will use the ``templates/mytemplate.jinja2`` 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`.
@@ -175,67 +164,110 @@ application. Without being processed by ``scan``, the decorator effectively
does nothing. ``@view_config`` is inert without being detected via a
:term:`scan`.
-The sample ``my_view()`` created by the scaffold uses a ``try:`` and ``except:``
-clause to detect if there is a problem accessing the project database and
-provide an alternate error response. That response will include the text
-shown at the end of the file, which will be displayed in the browser to
-inform the user about possible actions to take to solve the problem.
+The sample ``my_view()`` created by the scaffold uses a ``try:`` and
+``except:`` clause to detect if there is a problem accessing the project
+database and provide an alternate error response. That response will include
+the text shown at the end of the file, which will be displayed in the browser
+to inform the user about possible actions to take to solve the problem.
+
-Content Models with ``models.py``
----------------------------------
+Content models with the ``models`` package
+------------------------------------------
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``
+querying the SQL database. The ``models`` package is where the ``alchemy``
scaffold put the classes that implement our models.
-Open ``tutorial/tutorial/models.py``. It should already contain the following:
+First, open ``tutorial/tutorial/models/__init__.py``, which should already
+contain the following:
- .. literalinclude:: src/basiclayout/tutorial/models.py
+ .. literalinclude:: src/basiclayout/tutorial/models/__init__.py
:linenos:
:language: py
-Let's examine this in detail. First, we need some imports to support later code:
+Our ``__init__.py`` will perform some imports to support later code, then calls
+the function :func:`sqlalchemy.orm.configure_mappers`.
+
+Next open ``tutorial/tutorial/models/meta.py``, which should already contain
+the following:
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :end-before: DBSession
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
:linenos:
:language: py
-Next we set up a SQLAlchemy ``DBSession`` object:
+``meta.py`` contains imports that are used to support later code. We create a
+dictionary ``NAMING_CONVENTION`` as well.
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :lines: 17
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
+ :end-before: metadata
+ :linenos:
+ :language: py
+
+Next we create a ``metadata`` object from the class
+:class:`sqlalchemy.schema.MetaData`, using ``NAMING_CONVENTION`` as the value
+for the ``naming_convention`` argument. We also need to create a declarative
+``Base`` object to use as a base class for our model. Then our model classes
+will inherit from the ``Base`` class so they can be associated with our
+particular database connection.
+
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
+ :lines: 18-19
+ :lineno-start: 18
+ :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.
+Next we define several functions, the first of which is ``includeme``, which
+configures various database settings by calling subsequently defined functions.
+
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
+ :pyobject: includeme
+ :lineno-start: 22
+ :linenos:
+ :language: py
+
+The function ``get_session`` registers a database session with a transaction
+manager, and returns a ``dbsession`` object. With the transaction manager, our
+application will automatically issue a transaction commit after every request
+unless an exception is raised, in which case the transaction will be aborted.
+
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
+ :pyobject: get_session
+ :lineno-start: 35
+ :linenos:
+ :language: py
-We also need to create a declarative ``Base`` object to use as a
-base class for our model:
+The ``get_engine`` function creates an :term:`SQLAlchemy` database engine using
+:func:`sqlalchemy.engine_from_config` from the ``sqlalchemy.``-prefixed
+settings in the ``development.ini`` file's ``[app:main]`` section, which is a
+URI, something like ``sqlite://``.
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :lines: 18
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
+ :pyobject: get_engine
+ :lineno-start: 42
+ :linenos:
:language: py
-Our model classes will inherit from this ``Base`` class so they can be
-associated with our particular database connection.
+The function ``get_dbmaker`` accepts an :term:`SQLAlchemy` database engine,
+and creates a database session object ``dbmaker`` from the :term:`SQLAlchemy`
+class :class:`sqlalchemy.orm.session.sessionmaker`, which is then used for
+creating a session with the database engine.
+
+ .. literalinclude:: src/basiclayout/tutorial/models/meta.py
+ :pyobject: get_dbmaker
+ :lineno-start: 46
+ :linenos:
+ :language: py
-To give a simple example of a model class, we define one named ``MyModel``:
+To give a simple example of a model class, we define one named ``MyModel``:
- .. literalinclude:: src/basiclayout/tutorial/models.py
+ .. literalinclude:: src/basiclayout/tutorial/models/mymodel.py
:pyobject: MyModel
:linenos:
:language: py
Our example model does not require an ``__init__`` method because SQLAlchemy
-supplies for us a default constructor if one is not already present,
-which accepts keyword arguments of the same name as that of the mapped attributes.
+supplies for us a default constructor if one is not already present, which
+accepts keyword arguments of the same name as that of the mapped attributes.
.. note:: Example usage of MyModel:
@@ -247,8 +279,8 @@ The ``MyModel`` class has a ``__tablename__`` attribute. This informs
SQLAlchemy which table to use to store the data representing instances of this
class.
-The Index import and the Index object creation is not required for this
-tutorial, and will be removed in the next step.
-
That's about all there is to it regarding models, views, and initialization
code in our stock application.
+
+The Index import and the Index object creation is not required for this
+tutorial, and will be removed in the next step.