From 6ed41a034df40dcc6632432544742ebefe3162ba Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 20 Mar 2011 18:08:58 -0400 Subject: review changes to sqla tutorial --- docs/tutorials/wiki2/authorization.rst | 77 ++++++----- docs/tutorials/wiki2/basiclayout.rst | 57 ++++---- docs/tutorials/wiki2/definingmodels.rst | 40 +++--- docs/tutorials/wiki2/definingviews.rst | 223 +++++++++++++++----------------- 4 files changed, 191 insertions(+), 206 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst index 0f3a9c31c..64cab30db 100644 --- a/docs/tutorials/wiki2/authorization.rst +++ b/docs/tutorials/wiki2/authorization.rst @@ -27,13 +27,13 @@ Adding A Root Factory ~~~~~~~~~~~~~~~~~~~~~ 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. In -order for :app:`Pyramid` declarative security to work properly, the -context object generated during a request must 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. 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`. We'll modify our ``__init__.py``, passing in a :term:`root factory` to our :term:`Configurator` constructor. We'll point it at a new class we create @@ -45,19 +45,17 @@ inside our ``models.py`` file. Add the following statements to your :linenos: :language: python -The ``RootFactory`` class we've just added will be used by -:app:`Pyramid` to construct a ``context`` object. The context is -attached to the request object passed to our view callables as the -``context`` attribute. +The ``RootFactory`` class we've just added will be used by :app:`Pyramid` to +construct a ``context`` object. The context is attached to the request +object passed to our view callables as the ``context`` attribute. -All of our context objects will possess an ``__acl__`` attribute that -allows :data:`pyramid.security.Everyone` (a special principal) to -view all pages, while allowing only a :term:`principal` named -``group:editors`` to edit and add pages. The ``__acl__`` attribute -attached 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. +The context object generated by our root factory will possess an ``__acl__`` +attribute that allows :data:`pyramid.security.Everyone` (a special principal) +to view all pages, while allowing only a :term:`principal` named +``group:editors`` to edit and add pages. The ``__acl__`` attribute attached +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 to create route contexts may differ per-route as opposed to globally. See @@ -94,35 +92,36 @@ 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`: +We'll also change ``__init__.py``, adding a call to +:meth:`pyramid.config.Configurator.add_view` that points at our ``login`` +:term:`view callable`. This is 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. +A forbidden view 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 -``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. +We'll also 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 -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 ``view_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. Viewing Your Changes ~~~~~~~~~~~~~~~~~~~~ @@ -186,8 +185,8 @@ Changing Existing Views ~~~~~~~~~~~~~~~~~~~~~~~ Then we need to change each of our ``view_page``, ``edit_page`` and -``add_page`` views in ``views.py`` to pass a "logged in" parameter to -its template. We'll add something like this to each view body: +``add_page`` views in ``views.py`` to pass a "logged in" parameter to its +template. We'll add something like this to each view body: .. ignore-next-block .. code-block:: python @@ -196,8 +195,8 @@ its template. We'll add something like this to each view body: from pyramid.security import authenticated_userid logged_in = authenticated_userid(request) -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.: .. ignore-next-block .. code-block:: python diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst index c73009eb0..4d3496788 100644 --- a/docs/tutorials/wiki2/basiclayout.rst +++ b/docs/tutorials/wiki2/basiclayout.rst @@ -2,10 +2,9 @@ Basic Layout ============ -The starter files generated by the ``pyramid_routesalchemy`` template -are basic, but they provide a good orientation for the high-level -patterns common to most :term:`url dispatch` -based :app:`Pyramid` -projects. +The starter files generated by the ``pyramid_routesalchemy`` template are +basic, but they provide a good orientation for the high-level patterns common +to most :term:`url dispatch` -based :app:`Pyramid` projects. The source code for this tutorial stage can be browsed at `http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/basiclayout/ @@ -32,9 +31,9 @@ First we need some imports to support later code: :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 +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 @@ -55,10 +54,10 @@ The next step is to construct a :term:`Configurator`: :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``, +``settings`` is passed to the Configurator as a keyword argument with the +dictionary values passed by PasteDeploy as the ``**settings`` argument. This +will be a dictionary of settings parsed from the ``.ini`` file, 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 @@ -85,18 +84,19 @@ used when the URL is ``/``: :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. +Since this route has a ``pattern`` equalling ``/`` it is the route that will +be called when the URL ``/`` is visted, e.g. ``http://localhost:6543/``. 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. +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: @@ -105,7 +105,7 @@ method to return a :term:`WSGI` application: :lines: 15 :language: py -Our final __init__.py file will look like this: +Our final ``__init__.py`` file will look like this: .. literalinclude:: src/basiclayout/tutorial/__init__.py :linenos: @@ -148,12 +148,11 @@ 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``, 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. Next we define a function named ``populate`` which adds a single model instance into our SQL storage and commits a transaction: diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst index 117442a1c..7e8555190 100644 --- a/docs/tutorials/wiki2/definingmodels.rst +++ b/docs/tutorials/wiki2/definingmodels.rst @@ -37,28 +37,27 @@ SQLAlchemy models are easier to use than directly-mapped ones. :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`` -table. The ``id`` attribute will be the primary key in the table. The -``name`` attribute will be a text attribute, each value of which needs to be -unique within the column. The ``data`` attribute is a text attribute that -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. +``__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`` table. The ``id`` attribute will be the primary key +in the table. The ``name`` attribute will be a text attribute, each value of +which needs to be unique within the column. The ``data`` attribute is a text +attribute that 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. .. 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``. +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``. @@ -76,11 +75,10 @@ something like this: Viewing the Application in a Browser ------------------------------------ -We can't. At this point, our system is in a "non-runnable" state; -we'll need to change view-related files in the next chapter to be able -to start the application successfully. If you try to start the -application, you'll wind up with a Python traceback on your console -that ends with this exception: +We can't. At this point, our system is in a "non-runnable" state; we'll need +to change view-related files in the next chapter to be able to start the +application successfully. If you try to start the application, you'll wind +up with a Python traceback on your console that ends with this exception: .. code-block:: text diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst index 3fa9bbccd..874c49d4c 100644 --- a/docs/tutorials/wiki2/definingviews.rst +++ b/docs/tutorials/wiki2/definingviews.rst @@ -2,10 +2,10 @@ Defining Views ============== -A :term:`view callable` in a :term:`url dispatch` -based -:app:`Pyramid` application is typically a simple Python function that -accepts a single parameter named :term:`request`. A view callable is -assumed to return a :term:`response` object. +A :term:`view callable` in a :term:`url dispatch` -based :app:`Pyramid` +application is typically a simple Python function that accepts a single +parameter named :term:`request`. A view callable is assumed to return a +:term:`response` object. .. note:: A :app:`Pyramid` view can also be defined as callable which accepts *two* arguments: a :term:`context` and a @@ -23,11 +23,11 @@ assumed to return a :term:`response` object. The request passed to every view that is called as the result of a route match has an attribute named ``matchdict`` that contains the elements placed into the URL by the ``pattern`` of a ``route`` statement. For instance, if a -call to :meth:`pyramid.config.Configurator.add_route` in -``__init__.py`` had the pattern ``{one}/{two}``, and the URL at -``http://example.com/foo/bar`` was invoked, matching this pattern, the -matchdict dictionary attached to the request passed to the view would have a -``one`` key with the value ``foo`` and a ``two`` key with the value ``bar``. +call to :meth:`pyramid.config.Configurator.add_route` in ``__init__.py`` had +the pattern ``{one}/{two}``, and the URL at ``http://example.com/foo/bar`` +was invoked, matching this pattern, the matchdict dictionary attached to the +request passed to the view would have a ``one`` key with the value ``foo`` +and a ``two`` key with the value ``bar``. The source code for this tutorial stage can be browsed at `http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/views/ @@ -36,13 +36,13 @@ The source code for this tutorial stage can be browsed at Declaring Dependencies in Our ``setup.py`` File =============================================== -The view code in our application will depend on a package which is not -a dependency of the original "tutorial" application. The original -"tutorial" application was generated by the ``paster create`` command; -it doesn't know about our custom application requirements. We need to -add a dependency on the ``docutils`` package to our ``tutorial`` -package's ``setup.py`` file by assigning this dependency to the -``install_requires`` parameter in the ``setup`` function. +The view code in our application will depend on a package which is not a +dependency of the original "tutorial" application. The original "tutorial" +application was generated by the ``paster create`` command; it doesn't know +about our custom application requirements. We need to add a dependency on +the ``docutils`` package to our ``tutorial`` package's ``setup.py`` file by +assigning this dependency to the ``install_requires`` parameter in the +``setup`` function. Our resulting ``setup.py`` should look like so: @@ -58,45 +58,43 @@ Our resulting ``setup.py`` should look like so: Adding View Functions ===================== -We'll get rid of our ``my_view`` view function in our ``views.py`` -file. It's only an example and isn't relevant to our application. +We'll get rid of our ``my_view`` view function in our ``views.py`` file. +It's only an example and isn't relevant to our application. Then we're going to add four :term:`view callable` functions to our -``views.py`` module. One view callable (named ``view_wiki``) will -display the wiki itself (it will answer on the root URL), another -named ``view_page`` will display an individual page, another named -``add_page`` will allow a page to be added, and a final view callable -named ``edit_page`` will allow a page to be edited. We'll describe -each one briefly and show the resulting ``views.py`` file afterward. +``views.py`` module. One view callable (named ``view_wiki``) will display +the wiki itself (it will answer on the root URL), another named ``view_page`` +will display an individual page, another named ``add_page`` will allow a page +to be added, and a final view callable named ``edit_page`` will allow a page +to be edited. We'll describe each one briefly and show the resulting +``views.py`` file afterward. .. note:: - There is nothing special about the filename ``views.py``. A project - may have many view callables throughout its codebase in - arbitrarily-named files. Files implementing view callables often - have ``view`` in their filenames (or may live in a Python subpackage - of your application package named ``views``), but this is only by - convention. + There is nothing special about the filename ``views.py``. A project may + have many view callables throughout its codebase in arbitrarily-named + files. Files implementing view callables often have ``view`` in their + filenames (or may live in a Python subpackage of your application package + named ``views``), but this is only by convention. 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". +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". .. 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 -``FrontPage`` page (e.g. ``http://localhost:6543/FrontPage``), and -will use it as the "location" of the HTTPFound response, forming an -HTTP redirect. +The ``view_wiki`` function 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 ``FrontPage`` +page (e.g. ``http://localhost:6543/FrontPage``), and will use it as the +"location" of the HTTPFound response, forming an HTTP redirect. The ``view_page`` view function ------------------------------- @@ -114,76 +112,70 @@ compiled regular expression. :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 -already contains a page with the matched WikiWord name, the ``check`` -function generates a view link to be used as the substitution value -and returns it. If the wiki does not already contain a page with with -the matched WikiWord name, the function generates an "add" link as the -substitution value and returns it. - -As a result, the ``content`` variable is now a fully formed bit of -HTML containing various view and add links for WikiWords based on the -content of our current page object. - -We then generate an edit URL (because it's easier to do here than in -the template), and we return a dictionary with a number of arguments. -The fact that this view 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``. +``wikiwords.sub``, indicating that it should be called to provide a value for +each WikiWord match found in the content. If the wiki already contains a +page with the matched WikiWord name, the ``check`` function generates a view +link to be used as the substitution value and returns it. If the wiki does +not already contain a page with with the matched WikiWord name, the function +generates an "add" link as the substitution value and returns it. + +As a result, the ``content`` variable is now a fully formed bit of HTML +containing various view and add links for WikiWords based on the content of +our current page object. + +We then generate an edit URL (because it's easier to do here than in the +template), and we return a dictionary with a number of arguments. The fact +that this view 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``. The ``add_page`` view function ------------------------------ -The ``add_page`` function will be 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. +The ``add_page`` function will be 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. .. 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`` -value in the matchdict will be ``SomeName``. +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`` value in +the matchdict will be ``SomeName``. If the view execution is *not* a result of a form submission (if 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 use 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. - -If the view execution *is* a result of a form submission (if the -expression ``'form.submitted' in request.params`` is ``True``), we -scrape the page body from the form data, create a Page object using -the name in the matchdict ``pagename``, and obtain the page body from -the request, and save it into the database using ``session.add``. We -then redirect back to the ``view_page`` view (the :term:`default view` -for a Page) for the newly created page. +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 use 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. + +If the view execution *is* a result of a form submission (if the expression +``'form.submitted' in request.params`` is ``True``), we scrape the page body +from the form data, create a Page object using the name in the matchdict +``pagename``, and obtain the page body from the request, and save it into the +database using ``session.add``. We then redirect back to the ``view_page`` +view (the :term:`default view` for a Page) for the newly created page. The ``edit_page`` view function ------------------------------- -The ``edit_page`` function will be invoked when a user clicks the -"Edit this Page" button on the view form. It renders an edit form but -it also acts as the handler for the form it renders. The -``matchdict`` attribute of the request passed to the ``edit_page`` view -will have a ``pagename`` key matching the name of the page the user -wants to edit. +The ``edit_page`` function will be invoked when a user clicks the "Edit this +Page" button on the view form. It renders an edit form but it also acts as +the handler for the form it renders. The ``matchdict`` attribute of the +request passed to the ``edit_page`` view 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 @@ -191,10 +183,9 @@ wants to edit. :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 -object, and a save_url which will be used as the action of the -generated form. +expression ``'form.submitted' in request.params`` is ``False``), the view +simply renders the edit form, passing the request, 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 ``'form.submitted' in request.params`` is ``True``), the view grabs the @@ -222,15 +213,14 @@ 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: +Once we're done with the ``view.pt`` template, it will look a lot like the +below: .. literalinclude:: src/views/tutorial/templates/view.pt :language: xml @@ -248,13 +238,12 @@ the below: The ``edit.pt`` Template ------------------------ -The ``edit.pt`` template is used for adding and editing a wiki page. -It is used by the ``add_page`` and ``edit_page`` view functions. It -should display a page containing a form that POSTs back to the -"save_url" argument supplied by the view. The form should have a -"body" textarea field (the page data), and a submit button that has -the name "form.submitted". The textarea in the form should be filled -with any existing page data when it is rendered. +The ``edit.pt`` template is used for adding and editing a wiki page. It is +used by the ``add_page`` and ``edit_page`` view functions. It should display +a page containing a form that POSTs back to the "save_url" argument supplied +by the view. The form should have a "body" textarea field (the page data), +and a submit button that has the name "form.submitted". The textarea in the +form should be filled with any existing page data when it is rendered. Once we're done with the ``edit.pt`` template, it will look a lot like the below: @@ -267,8 +256,8 @@ Static Assets Our templates name a single static asset named ``pylons.css``. We don't need to create this file within our package's ``static`` directory because it was -provided at the time we created the project. This file is a little too long to -replicate within the body of this guide, however it is available `online +provided at the time we created the project. This file is a little too long +to replicate within the body of this guide, however it is available `online `_. This CSS file will be accessed via @@ -276,8 +265,8 @@ e.g. ``http://localhost:6543/static/pylons.css`` by virtue of the call to ``add_static_view`` directive we've made in the ``__init__`` file. Any number and type of static assets can be placed in this directory (or subdirectories) and are just referred to by URL or by using the convenience -method ``static_url`` e.g. ``request.static_url('{{package}}:static/foo.css')`` -within templates. +method ``static_url`` +e.g. ``request.static_url('{{package}}:static/foo.css')`` within templates. Mapping Views to URLs in ``__init__.py`` ======================================== -- cgit v1.2.3