summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorCarlos de la Guardia <cguardia@hal9001.(none)>2011-03-15 20:35:02 -0400
committerCarlos de la Guardia <cguardia@hal9001.(none)>2011-03-15 20:35:02 -0400
commit0aed1cdd37fb57663b978d1d8728d5b652b0b092 (patch)
tree09057b3bf9ee1a397694e884ff225a599be7f6f1 /docs
parent9fd15137314f304559479c1846d930a36b0e772e (diff)
downloadpyramid-0aed1cdd37fb57663b978d1d8728d5b652b0b092.tar.gz
pyramid-0aed1cdd37fb57663b978d1d8728d5b652b0b092.tar.bz2
pyramid-0aed1cdd37fb57663b978d1d8728d5b652b0b092.zip
Restructured the routes wiki tutorial to make it easier to follow along. Moved the routes tutorial above the traversal tutorial.
Diffstat (limited to 'docs')
-rw-r--r--docs/index.rst2
-rw-r--r--docs/tutorials/wiki2/authorization.rst63
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst200
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst24
-rw-r--r--docs/tutorials/wiki2/definingviews.rst28
-rw-r--r--docs/tutorials/wiki2/installation.rst61
6 files changed, 220 insertions, 158 deletions
diff --git a/docs/index.rst b/docs/index.rst
index d55daccfe..d9a95f647 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -76,8 +76,8 @@ applications to various platforms.
.. toctree::
:maxdepth: 2
- tutorials/wiki/index.rst
tutorials/wiki2/index.rst
+ tutorials/wiki/index.rst
tutorials/bfg/index.rst
tutorials/gae/index.rst
tutorials/modwsgi/index.rst
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index fef74e4e2..0f3a9c31c 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -40,16 +40,10 @@ We'll modify our ``__init__.py``, passing in a :term:`root factory` to our
inside our ``models.py`` file. Add the following statements to your
``models.py`` file:
-.. code-block:: python
-
- from pyramid.security import Allow
- from pyramid.security import Everyone
-
- class RootFactory(object):
- __acl__ = [ (Allow, Everyone, 'view'),
- (Allow, 'group:editors', 'edit') ]
- def __init__(self, request):
- pass
+.. literalinclude:: src/authorization/tutorial/models.py
+ :lines: 3-4,45-49
+ :linenos:
+ :language: python
The ``RootFactory`` class we've just added will be used by
:app:`Pyramid` to construct a ``context`` object. The context is
@@ -84,16 +78,45 @@ For any :app:`Pyramid` application to perform authorization, we need to add a
We'll change our ``__init__.py`` file to enable an
``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to enable
-declarative security checking. We'll also change ``__init__.py`` to add a
-:meth:`pyramid.config.Configurator.add_view` call to points at our
-``login`` :term:`view callable`, also known as a :term:`forbidden view`.
+declarative security checking.
+
+.. literalinclude:: src/authorization/tutorial/__init__.py
+ :lines: 15-21
+ :linenos:
+ :language: python
+
+Note that that the
+:class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor
+accepts two arguments: ``secret`` and ``callback``. ``secret`` is a string
+representing an encryption key used by the "authentication ticket" machinery
+represented by this policy: it is required. The ``callback`` is a string,
+representing a :term:`dotted Python name`, which points at the
+``groupfinder`` function in the current directory's ``security.py`` file. We
+haven't added that module yet, but we're about to.
+
+We'll also change ``__init__.py`` to add a
+:meth:`pyramid.config.Configurator.add_view` call that points at our
+``login`` :term:`view callable`, also known as a :term:`forbidden view`:
+
+.. literalinclude:: src/authorization/tutorial/__init__.py
+ :lines: 24-26
+ :linenos:
+ :language: python
+
This configures our newly created login view to show up when :app:`Pyramid`
-detects that a view invocation can not be authorized. Also, we'll add
+detects that a view invocation can not be authorized.
+
+Also, we'll add
``view_permission`` arguments with the value ``edit`` to the ``edit_page``
and ``add_page`` routes. This indicates that the view callables which these
routes reference cannot be invoked without the authenticated user possessing
the ``edit`` permission with respect to the current context.
+.. literalinclude:: src/authorization/tutorial/__init__.py
+ :lines: 32-39
+ :linenos:
+ :language: python
+
This makes 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
@@ -111,16 +134,6 @@ and adding views, your application's ``__init__.py`` will look like this:
:linenos:
:language: python
-Note that that the
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor
-accepts two arguments: ``secret`` and ``callback``. ``secret`` is a string
-representing an encryption key used by the "authentication ticket" machinery
-represented by this policy: it is required. The ``callback`` is a string,
-representing a :term:`dotted Python name`, which points at the
-``groupfinder`` function in the current directory's ``security.py`` file. We
-haven't added that module yet, but we're about to.
-
-
Adding ``security.py``
~~~~~~~~~~~~~~~~~~~~~~
@@ -161,7 +174,7 @@ provide a link to it. This view will clear the credentials of the
logged in user and redirect back to the front page.
We'll add a different file (for presentation convenience) to add login
-and logout view callables. Add a file named ``login.py`` to your
+and the logout view callables. Add a file named ``login.py`` to your
application (in the same directory as ``views.py``) with the following
content:
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 17dcfc48f..c73009eb0 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -23,58 +23,93 @@ The generated ``development.ini`` file is read by ``paster`` which looks for
the application module in the ``use`` variable of the ``app:tutorial``
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 the following ``main``
-function:
+point* is defined as ``tutorial:main`` and points to a function named ``main``.
+
+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:tutorial]`` section. This will be a URI (something like
+``sqlite://``):
.. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 6-9
:linenos:
:language: py
-#. *Lines 1-4*. Imports to support later code.
-
-#. *Line 9*. Create a SQLAlchemy database engine from the ``sqlalchemy.``
- prefixed settings in the ``development.ini`` file's ``[app:tutorial]``
- section. This will be a URI (something like ``sqlite://``).
-
-#. *Line 10*. We initialize our SQL database using SQLAlchemy, passing
- it the engine
-
-#. *Line 11*. We construct a :term:`Configurator`. ``settings`` is
- passed as a keyword argument with the dictionary values passed by
- PasteDeploy as the ``settings`` argument. This will be a
- dictionary of settings parsed by PasteDeploy, which contains
- deployment-related values such as ``reload_templates``,
- ``db_string``, etc.
-
-#. *Line 12*. We call
- :meth:`pyramid.config.Configurator.add_static_view` with the
- arguments ``static`` (the name), and ``tutorial:static`` (the path). 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.
-
-#. *Lines 13-14*. Register a :term:`route configuration` via the
- :meth:`pyramid.config.Configurator.add_route` method that will be
- used when the URL is ``/``. Since this route has a ``pattern`` equalling
- ``/`` it is the "default" route. The argument named ``view`` with the
- value ``tutorial.views.my_view`` is the dotted name to a *function* we
- write (generated by the ``pyramid_routesalchemy`` template) that is given
- a ``request`` object and which returns a response or a dictionary. You
- will use :meth:`pyramid.config.Configurator.add_route` statements
- in a :term:`URL dispatch` based application to map URLs to code. This
- route also names a ``view_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.
-
-#. *Line 15*. We use the
- :meth:`pyramid.config.Configurator.make_wsgi_app` method to return
- a :term:`WSGI` application.
+We then initialize 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`:
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 11
+ :language: py
+
+``settings`` is passed as a keyword argument with the dictionary values
+passed by PasteDeploy as the ``settings`` argument. This will be a
+dictionary of settings parsed by PasteDeploy, which contains
+deployment-related values such as ``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):
+
+ .. 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.
+
+Using the configurator we can also register a :term:`route configuration`
+via the :meth:`pyramid.config.Configurator.add_route` method that will be
+used when the URL is ``/``:
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 13-14
+ :language: py
+
+Since this route has a ``pattern`` equalling
+``/`` it is the "default" route. The argument named ``view`` with the
+value ``tutorial.views.my_view`` is the dotted name to a *function* we
+write (generated by the ``pyramid_routesalchemy`` template) that is given
+a ``request`` object and which returns a response or a dictionary.
+
+You will use :meth:`pyramid.config.Configurator.add_route` statements
+in a :term:`URL dispatch` based application to map URLs to code. This
+route also names a ``view_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.
+
+Fimnally, we use the :meth:`pyramid.config.Configurator.make_wsgi_app`
+method to return a :term:`WSGI` application:
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 15
+ :language: py
+
+Our final __init__.py file will look like this:
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :linenos:
+ :language: py
Content Models with ``models.py``
---------------------------------
@@ -85,34 +120,65 @@ SQLAlchemy is an "object relational mapper" (an ORM). The
``models.py`` file is where the ``pyramid_routesalchemy`` Paster
template put the classes that implement our models.
-Here is the source for ``models.py``:
+Let's take a look. First, we need some imports to support later code.
.. literalinclude:: src/basiclayout/tutorial/models.py
+ :end-before: DBSession
:linenos:
:language: py
-#. *Lines 1-13*. Imports to support later code.
+Next we set up a SQLAlchemy "DBSession" object:
+
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :lines: 15-16
+ :linenos:
+ :language: py
-#. *Line 15*. We set up a SQLAlchemy "DBSession" object here. We
- specify that we'd like to use the "ZopeTransactionExtension". This
- extension is an extension which allows us to use a *transaction
- manager* instead of controlling commits and aborts to database
- operations by hand.
+We also need to create a declarative ``Base`` object to use as a
+base class for our model:
-#. *Line 16*. We create a declarative ``Base`` object to use as a
- base class for our model.
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :lines: 17
+ :language: py
+
+To give a simple example of a model class, we define one named ``MyModel``:
+
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :pyobject: MyModel
+ :linenos:
+ :language: py
-#. *Lines 18-26*. A model class named ``MyModel``. It 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 store the data representing instances of this class.
+Our sample 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 store the data representing instances of this class.
-#. *Lines 28-33*. A function named ``populate`` which adds a single
- model instance into our SQL storage and commits a transaction.
+Next we define a function named ``populate`` which adds a single
+model instance into our SQL storage and commits a transaction:
-#. *Lines 35-42*. A function named ``initialize_sql`` which receives a SQL
- database engine and binds it to our SQLAlchemy DBSession object. It also
- calls the ``populate`` function, to do initial database population.
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :pyobject: populate
+ :linenos:
+ :language: py
+
+The function doesn't do a lot in this case, but it's there to illustrate
+how an application requiring many objects to be set up could work.
+
+Lastly we have a function named ``initialize_sql`` which receives a SQL
+database engine and binds it to our SQLAlchemy DBSession object. It also
+calls the ``populate`` function, to do initial database population. This
+is the initialization function that is called from __init__.py above.
+
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :pyobject: initialize_sql
+ :linenos:
+ :language: py
+
+Here is the complete source for ``models.py``:
+
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :linenos:
+ :language: py
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index 09e1f26c3..117442a1c 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -31,8 +31,14 @@ application, this class should inherit from an instance of
:class:`sqlalchemy.ext.declarative.declarative_base`. Declarative
SQLAlchemy models are easier to use than directly-mapped ones.
-Our ``Page`` class will have a class level attribute ``__tablename__`` which
-equals the string ``pages``. This means that SQLAlchemy will store our wiki
+.. literalinclude:: src/models/tutorial/models.py
+ :pyobject: Page
+ :linenos:
+ :language: python
+
+As you can see, our ``Page`` class has a class level attribute
+``__tablename__`` which equals the string ``pages``.
+This means that SQLAlchemy will store our wiki
data in a SQL table named ``pages``. Our Page class will also have
class-level attributes named ``id``, ``pagename`` and ``data`` (all instances
of :class:`sqlalchemy.Column`). These will map to columns in the ``pages``
@@ -44,15 +50,21 @@ will hold the body of each page.
We'll also remove our ``populate`` function. We'll inline the
populate step into ``initialize_sql``, changing our ``initialize_sql``
function to add a FrontPage object to our database at startup time.
-We're also going to use slightly different binding syntax. It will
-will otherwise largely be the same as the ``initialize_sql`` in the
+
+.. literalinclude:: src/models/tutorial/models.py
+ :pyobject: initialize_sql
+ :linenos:
+ :language: python
+
+Here, we're using a slightly different binding syntax. It is
+otherwise largely the same as the ``initialize_sql`` in the
paster-generated ``models.py``.
Our DBSession assignment stays the same as the original generated
``models.py``.
-Looking at the Result of Our Edits to ``models.py``
----------------------------------------------------
+Looking at the Result of all Our Edits to ``models.py``
+-------------------------------------------------------
The result of all of our edits to ``models.py`` will end up looking
something like this:
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index 73f728132..3fa9bbccd 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -83,7 +83,14 @@ The ``view_wiki`` view function
The ``view_wiki`` function will respond as the :term:`default view` of
a ``Wiki`` model object. It always redirects to a URL which
-represents the path to our "FrontPage". It returns an instance of the
+represents the path to our "FrontPage".
+
+.. literalinclude:: src/views/tutorial/views.py
+ :pyobject: view_wiki
+ :linenos:
+ :language: python
+
+It returns an instance of the
:class:`pyramid.httpexceptions.HTTPFound` class (instances of which
implement the WebOb :term:`response` interface), It will use the
:func:`pyramid.url.route_url` API to construct a URL to the
@@ -101,6 +108,11 @@ attribute of a Page object) as HTML. Then it substitutes an HTML
anchor for each *WikiWord* reference in the rendered HTML using a
compiled regular expression.
+.. literalinclude:: src/views/tutorial/views.py
+ :pyobject: view_page
+ :linenos:
+ :language: python
+
The curried function named ``check`` is used as the first argument to
``wikiwords.sub``, indicating that it should be called to provide a
value for each WikiWord match found in the content. If the wiki
@@ -134,6 +146,11 @@ 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
+ :pyobject: add_page
+ :linenos:
+ :language: python
+
The matchdict will have a ``pagename`` key that matches the name of
the page we'd like to add. If our add view is invoked via,
e.g. ``http://localhost:6543/add_page/SomeName``, the ``pagename``
@@ -168,6 +185,11 @@ it also acts as the handler for the form it renders. The
will have a ``pagename`` key matching the name of the page the user
wants to edit.
+.. literalinclude:: src/views/tutorial/views.py
+ :pyobject: edit_page
+ :linenos:
+ :language: python
+
If the view execution is *not* a result of a form submission (if the
expression ``'form.submitted' in request.params`` is ``False``), the
view simply renders the edit form, passing the request, the page
@@ -180,8 +202,8 @@ If the view execution *is* a result of a form submission (if the expression
attribute of the page object. It then redirects to the default view of the
wiki page, which will always be the ``view_page`` view.
-Viewing the Result of Our Edits to ``views.py``
-===============================================
+Viewing the Result of all Our Edits to ``views.py``
+===================================================
The result of all of our edits to ``views.py`` will leave it looking
like this:
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index bee348de6..ed81e3774 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -2,10 +2,9 @@
Installation
============
-For the most part, the installation process for this tutorial
-duplicates the steps described in :ref:`installing_chapter` and
-:ref:`project_narr`, however it also explains how to install
-additional libraries for tutorial purposes.
+This tutorial assumes that Python and virtualenv are already installed
+and working in your system. If you need help setting this up, you should
+refer to the chapters on :ref:`installing_chapter`.
Preparation
===========
@@ -22,32 +21,7 @@ Preparation, UNIX
manager. For example, on a Debian Linux system, do ``sudo apt-get
install libsqlite3-dev``.
-#. If you don't already have a Python 2.6 interpreter installed on
- your system, obtain, install, or find `Python 2.6
- <http://www.python.org/download/releases/2.6.6/>`_ for your system.
-
-#. Make sure the Python development headers are installed on your system. If
- you've installed Python from source, these will already be installed. If
- you're using a system Python, you may have to install a ``python-dev``
- package (e.g. ``apt-get python-dev``). The headers are not required for
- Pyramid itself, just for dependencies of the tutorial.
-
-#. Install the latest `setuptools` into the Python you
- obtained/installed/found in the step above: download `ez_setup.py
- <http://peak.telecommunity.com/dist/ez_setup.py>`_ and run it using
- the ``python`` interpreter of your Python 2.6 installation:
-
- .. code-block:: text
-
- $ /path/to/my/Python-2.6/bin/python ez_setup.py
-
-#. Use that Python's `bin/easy_install` to install `virtualenv`:
-
- .. code-block:: text
-
- $ /path/to/my/Python-2.6/bin/easy_install virtualenv
-
-#. Use that Python's virtualenv to make a workspace:
+#. Use your Python's virtualenv to make a workspace:
.. code-block:: text
@@ -59,9 +33,6 @@ Preparation, UNIX
$ cd pyramidtut
-#. (Optional) Consider using ``source bin/activate`` to make your
- shell environment wired to use the virtualenv.
-
#. Use ``easy_install`` to get :app:`Pyramid` and its direct
dependencies installed:
@@ -79,26 +50,7 @@ Preparation, UNIX
Preparation, Windows
--------------------
-#. Install, or find `Python 2.6.6
- <http://python.org/download/releases/2.6.6/>`_ for your system.
-
-#. Install the latest `setuptools` into the Python you
- obtained/installed/found in the step above: download `ez_setup.py
- <http://peak.telecommunity.com/dist/ez_setup.py>`_ and run it using
- the ``python`` interpreter of your Python 2.6 installation using a
- command prompt:
-
- .. code-block:: text
-
- c:\> c:\Python26\python ez_setup.py
-
-#. Use that Python's `bin/easy_install` to install `virtualenv`:
-
- .. code-block:: text
-
- c:\> c:\Python26\Scripts\easy_install virtualenv
-
-#. Use that Python's virtualenv to make a workspace:
+#. Use your Python's virtualenv to make a workspace:
.. code-block:: text
@@ -110,9 +62,6 @@ Preparation, Windows
c:\> cd pyramidtut
-#. (Optional) Consider using ``bin\activate.bat`` to make your shell
- environment wired to use the virtualenv.
-
#. Use ``easy_install`` to get :app:`Pyramid` and its direct
dependencies installed: