Permalink
Browse files

Improve text of SQLAlchemy wiki tutorial.

A mixture of typo fixes and wording improvements.
  • Loading branch information...
1 parent 911b400 commit b3e608bac815a7d3fc639d78ec38edc5f97df859 @douglatornell douglatornell committed Mar 17, 2012
@@ -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.
@@ -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
@@ -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.
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -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
@@ -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:
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -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
@@ -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
@@ -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:
@@ -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
@@ -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
@@ -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).
@@ -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
@@ -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
@@ -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
@@ -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:
@@ -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
====================================
@@ -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
-------
@@ -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
--------
@@ -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
@@ -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
@@ -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::
.
----------------------------------------------------------------------
Oops, something went wrong.

0 comments on commit b3e608b

Please sign in to comment.