Skip to content

Commit

Permalink
Improve text of SQLAlchemy wiki tutorial.
Browse files Browse the repository at this point in the history
A mixture of typo fixes and wording improvements.
  • Loading branch information
douglatornell committed Mar 17, 2012
1 parent 911b400 commit b3e608b
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 90 deletions.
68 changes: 35 additions & 33 deletions docs/tutorials/wiki2/authorization.rst
Expand Up @@ -7,8 +7,8 @@ Adding Authorization
:app:`Pyramid` provides facilities for :term:`authentication` and
:term:`authorization`. We'll make use of both features to provide security
to our application. Our application currently allows anyone with access to
the server to view, edit, and add pages to our wiki. We'll change our
application to allow only people whom possess a specific username (`editor`)
the server to view, edit, and add pages to our wiki. We'll change that
to allow only people who possess a specific username (`editor`)
to add and edit wiki pages but we'll continue allowing anyone with access to
the server to view pages.

Expand Down Expand Up @@ -41,13 +41,12 @@ Open ``models.py`` and add the following statements:
:language: python

We're going to start to use a custom :term:`root factory` within our
``__init__.py`` file. The objects generated by the root factory will be used
as the :term:`context` of each request to our application. We do this to
allow :app:`Pyramid` declarative security to work properly. The context
object generated by the root factory during a request will be decorated with
security declarations. When we begin to use a custom root factory to generate
our contexts, we can begin to make use of the declarative security features
of :app:`Pyramid`.
``__init__.py`` file. The objects generated by the root factory will
be used as the :term:`context` of each request to our application.
Those context objects will be decorated with security
declarations. When we use a custom root factory to generate
our contexts, we can begin to make use of the declarative security
features of :app:`Pyramid`.

We'll modify our ``__init__.py``, passing in a :term:`root factory` to our
:term:`Configurator` constructor. We'll point it at the new class we created
Expand All @@ -65,7 +64,7 @@ to a context is interpreted specially by :app:`Pyramid` as an access control
list during view callable execution. See :ref:`assigning_acls` for more
information about what an :term:`ACL` represents.

.. note: Although we don't use the functionality here, the ``factory`` used
.. note:: Although we don't use the functionality here, the ``factory`` used
to create route contexts may differ per-route as opposed to globally. See
the ``factory`` argument to
:meth:`pyramid.config.Configurator.add_route` for more info.
Expand Down Expand Up @@ -147,9 +146,10 @@ We've given the ``editor`` user membership to the ``group:editors`` by
mapping him to this group in the ``GROUPS`` data structure (``GROUPS =
{'editor':['group:editors']}``). Since the ``groupfinder`` function
consults the ``GROUPS`` data structure, this will mean that, as a
result of the ACL attached to the root returned by the root factory,
and the permission associated with the ``add_page`` and ``edit_page``
views, the ``editor`` user should be able to add and edit pages.
result of the ACL attached to the :term:`context` object returned by
the root factory, and the permission associated with the ``add_page``
and ``edit_page`` views, the ``editor`` user should be able to add and
edit pages.

Adding Login and Logout Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -176,20 +176,20 @@ The ``logout`` view callable will look something like this:
:language: python

The ``login`` view callable is decorated with two decorators, a
``@view_config`` decorators, which associates it with the ``login`` route,
the other a ``@forbidden_view_config`` decorator which turns it in to an
:term:`exception view` when Pyramid raises a
:class:`pyramid.httpexceptions.HTTPForbidden` exception. The one which
associates it with the ``login`` route makes it visible when we visit
``/login``. The other one makes it a :term:`forbidden view`. The forbidden
view is displayed whenever Pyramid or your application raises an
HTTPForbidden exception. In this case, we'll be relying on the forbidden
view to show the login form whenver someone attempts to execute an action
which they're not yet authorized to perform.
``@view_config`` decorator, which associates it with the ``login``
route, and a ``@forbidden_view_config`` decorator which turns it in to
an :term:`exception view`. The one which associates it with the
``login`` route makes it visible when we visit ``/login``. The other
one makes it a :term:`forbidden view`. The forbidden view is
displayed whenever Pyramid or your application raises an
:class:`pyramid.httpexceptions.HTTPForbidden` exception. In this
case, we'll be relying on the forbidden view to show the login form
whenver someone attempts to execute an action which they're not yet
authorized to perform.

The ``logout`` view callable is decorated with a ``@view_config`` decorator
which associates it with the ``logout`` route. This makes it visible when we
visit ``/login``.
visit ``/logout``.

We'll need to import some stuff to service the needs of these two functions:
the ``pyramid.view.forbidden_view_config`` class, a number of values from the
Expand Down Expand Up @@ -222,8 +222,8 @@ something like this to each view body:
Return a logged_in flag to the renderer
---------------------------------------

We'll then change the return value of these views to pass the `resulting
`logged_in`` value to the template, e.g.:
We'll then change the return value of these views to pass the resulting
``logged_in`` value to the template, e.g.:

.. code-block:: python
:linenos:
Expand All @@ -248,12 +248,14 @@ callables which these views reference cannot be invoked without the
authenticated user possessing the ``edit`` permission with respect to the
current :term:`context`.

Adding these ``permission`` arguments causes Pyramid to make the assertion
that only users who possess the effective ``edit`` permission at the time of
the request may invoke those two views. We've granted the ``group:editors``
principal the ``edit`` permission at the root model via its ACL, so only the
a user whom is a member of the group named ``group:editors`` will able to
invoke the views associated with the ``add_page`` or ``edit_page`` routes.
Adding these ``permission`` arguments causes Pyramid to make the
assertion that only users who possess the effective ``edit``
permission at the time of the request may invoke those two views.
We've granted the ``group:editors`` :term:`principal` the ``edit``
permission in the :term:`root factory` via its ACL, so only a user who
is a member of the group named ``group:editors`` will be able to
invoke the views associated with the ``add_page`` or ``edit_page``
routes.

Adding the ``login.pt`` Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -322,7 +324,7 @@ each of the following URLs, check that the result is as expected:
- ``http://localhost:6543/FrontPage`` invokes
the ``view_page`` view of the FrontPage page object.

- ``http://localhost:6543/edit_page/FrontPage``
- ``http://localhost:6543/FrontPage/edit_page``
invokes the edit view for the FrontPage object. It is executable by
only the ``editor`` user. If a different user (or the anonymous
user) invokes it, a login form will be displayed. Supplying the
Expand Down
15 changes: 8 additions & 7 deletions docs/tutorials/wiki2/basiclayout.rst
Expand Up @@ -74,7 +74,7 @@ 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
``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
Expand Down Expand Up @@ -123,10 +123,11 @@ Finally, ``main`` is finished configuring things, so it uses the
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.
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:

Expand All @@ -151,7 +152,7 @@ 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, e.g. ``config.scan()``? 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
Expand Down Expand Up @@ -199,7 +200,7 @@ To give a simple example of a model class, we define one named ``MyModel``:
:linenos:
:language: py

Our sample model has an ``__init__`` that takes a two arguments (``name``,
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
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/wiki2/definingmodels.rst
Expand Up @@ -57,7 +57,7 @@ attribute that will hold the body of each page.
Changing ``scripts/initializedb.py``
------------------------------------

We haven't looked at the guts of this file yet, but within the ``scripts``
We haven't looked at the details of this file yet, but within the ``scripts``
directory of your ``tutorial`` package is a file named ``initializedb.py``. Code
in this file is executed whenever we run the ``initialize_tutorial_db`` command
(as we did in the installation step of this tutorial).
Expand Down
50 changes: 28 additions & 22 deletions docs/tutorials/wiki2/definingviews.rst
Expand Up @@ -157,17 +157,19 @@ that ``view_page()`` returns a dictionary (as opposed to a :term:`response`
object) is a cue to :app:`Pyramid` that it should try to use a :term:`renderer`
associated with the view configuration to render a template. In our case,
the template which will be rendered will be the ``templates/view.pt``
template, as per the configuration put into effect in ``__init__.py``.
template, as indicated in the ``@view_config`` decorator that is applied to
``view_page()``.

The ``add_page`` view function
------------------------------

``add_page()`` is invoked when a user clicks on a *WikiWord* which isn't yet
represented as a page in the system. The ``check`` function
within the ``view_page`` view generates URLs to this view. It also acts as a
handler for the form that is generated when we want to add a page object.
The ``matchdict`` attribute of the request passed to the ``add_page()`` view
will have the values we need to construct URLs and find model objects.
``add_page()`` is invoked when a user clicks on a *WikiWord* which
isn't yet represented as a page in the system. The ``check`` function
within the ``view_page`` view generates URLs to this view.
``add_page()`` also acts as a handler for the form that is generated
when we want to add a page object. The ``matchdict`` attribute of the
request passed to the ``add_page()`` view will have the values we need
to construct URLs and find model objects.

.. literalinclude:: src/views/tutorial/views.py
:lines: 45-56
Expand All @@ -179,17 +181,17 @@ the page we'd like to add. If our add view is invoked via,
e.g. ``http://localhost:6543/add_page/SomeName``, the value for
``'pagename'`` in the ``matchdict`` will be ``'SomeName'``.

If the view execution is *not* a result of a form submission (if the
If the view execution is *not* a result of a form submission (i.e. the
expression ``'form.submitted' in request.params`` is ``False``), the view
callable renders a template. To do so, it generates a "save url" which the
template uses as the form post URL during rendering. We're lazy here, so
we're trying to use the same template (``templates/edit.pt``) for the add
view as well as the page edit view, so we create a dummy Page object in order
to satisfy the edit form's desire to have *some* page object exposed as
``page``, and :app:`Pyramid` will render the template associated with this
view to a response.
we're going to use the same template (``templates/edit.pt``) for the add
view as well as the page edit view. To do so we create a dummy Page object
in order to satisfy the edit form's desire to have *some* page object
exposed as ``page``. :app:`Pyramid` will render the template associated
with this view to a response.

If the view execution *is* a result of a form submission (if the expression
If the view execution *is* a result of a form submission (i.e. the expression
``'form.submitted' in request.params`` is ``True``), we scrape the page body
from the form data, create a Page object with this page body and the name
taken from ``matchdict['pagename']``, and save it into the database using
Expand All @@ -210,12 +212,12 @@ matching the name of the page the user wants to edit.
:linenos:
:language: python

If the view execution is *not* a result of a form submission (if the
If the view execution is *not* a result of a form submission (i.e. the
expression ``'form.submitted' in request.params`` is ``False``), the view
simply renders the edit form, passing the page object and a ``save_url``
which will be used as the action of the generated form.

If the view execution *is* a result of a form submission (if the expression
If the view execution *is* a result of a form submission (i.e. the expression
``'form.submitted' in request.params`` is ``True``), the view grabs the
``body`` element of the request parameters and sets it as the ``data``
attribute of the page object. It then redirects to the ``view_page`` view
Expand All @@ -231,11 +233,12 @@ The views we've added all reference a :term:`template`. Each template is a
The ``view.pt`` Template
------------------------

The ``view.pt`` template is used for viewing a single wiki page. It is used
by the ``view_page`` view function. It should have a div that is "structure
replaced" with the ``content`` value provided by the view. It should also
have a link on the rendered page that points at the "edit" URL (the URL which
invokes the ``edit_page`` view for the page being viewed).
The ``view.pt`` template is used for viewing a single wiki page. It
is used by the ``view_page`` view function. It should have a ``div``
that is "structure replaced" with the ``content`` value provided by
the view. It should also have a link on the rendered page that points
at the "edit" URL (the URL which invokes the ``edit_page`` view for
the page being viewed).

Once we're done with the ``view.pt`` template, it will look a lot like the
below:
Expand Down Expand Up @@ -323,11 +326,14 @@ the order they're found in the ``__init__.py`` file.
``route_name='edit_page'``.

As a result of our edits, the ``__init__.py`` file should look
something like so:
something like:

.. literalinclude:: src/views/tutorial/__init__.py
:linenos:
:language: python
:emphasize-lines: 13-16

(The highlighted lines are the ones that need to be added or edited.)

Viewing the Application in a Browser
====================================
Expand Down
12 changes: 7 additions & 5 deletions docs/tutorials/wiki2/design.rst
Expand Up @@ -4,7 +4,7 @@ Design

Following is a quick overview of our wiki application, to help
us understand the changes that we will be doing next in our
default files generated by the paster scafffold.
default files generated by the ``alchemy`` scaffold.

Overall
-------
Expand Down Expand Up @@ -34,9 +34,10 @@ be used as the wiki home page.
Views
-----

There will be four views to handle the normal operations of
viewing, editing and adding wiki pages. Two additional views
will handle the login and logout tasks related to security.
There will be four views to handle the normal operations of adding and
editing wiki pages, and viewing pages and the wiki front page. Two
additional views will handle the login and logout tasks related to
security.

Security
--------
Expand All @@ -59,7 +60,8 @@ Security
| Allow | group:editors | Edit |
+----------+----------------+----------------+

- Permission declarations for the views.
- Permission declarations are added to the views to assert the
security policies as each request is handled.


Summary
Expand Down
8 changes: 4 additions & 4 deletions docs/tutorials/wiki2/distributing.rst
Expand Up @@ -27,12 +27,12 @@ The output of such a command will be something like:
running sdist
# ... more output ...
creating dist
tar -cf dist/tutorial-0.1.tar tutorial-0.1
gzip -f9 dist/tutorial-0.1.tar
removing 'tutorial-0.1' (and everything under it)
tar -cf dist/tutorial-0.0.tar tutorial-0.0
gzip -f9 dist/tutorial-0.0.tar
removing 'tutorial-0.0' (and everything under it)
Note that this command creates a tarball in the "dist" subdirectory
named ``tutorial-0.1.tar.gz``. You can send this file to your friends
named ``tutorial-0.0.tar.gz``. You can send this file to your friends
to show them your cool new application. They should be able to
install it by pointing the ``easy_install`` command directly at it.
Or you can upload it to `PyPI <http://pypi.python.org>`_ and share it
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/wiki2/installation.rst
Expand Up @@ -141,7 +141,7 @@ On Windows:
c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
For a successful test run, you should see output like this::
For a successful test run, you should see output that ends like this::

.
----------------------------------------------------------------------
Expand Down

0 comments on commit b3e608b

Please sign in to comment.