Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Demo documentation.

  • Loading branch information...
commit 79fafa8d6c14bc29dfbe89569b93d690d281908e 1 parent 83eb30d
Mike Orr mikeorr authored
Showing with 191 additions and 252 deletions.
  1. +71 −80 docs/demo/content.rst
  2. +119 −168 docs/demo/details.rst
  3. +1 −4 docs/demo/features.rst
151 docs/demo/content.rst
View
@@ -1,103 +1,94 @@
-Default templates and stylesheet
-================================
+Templates and stylesheets
+=========================
-The default home page was redesigned in Akhet 1.0 final to be a simple base you
-can start with and add to if you wish. It consists of four files:
+The demo's Mako templates and stylesheets are designed to function
+in a variety of environments, so you can copy them to your application as a starting
+point. The following files are included:
-* A home page, *zzz/templates/index.html*
-* A site template, *zzz/templates/site.html*
-* A stylesheet, *zzz/static/stylesheets/default.css*
-* A "reset" stylesheet, *zzz/static/stylesheets/reset.css*
+* A home page, *akhet_demo/templates/index.html*
+* A site template, *akhet_demo/templates/site.html*
+* A stylesheet, *akhet_demo/static/stylesheets/default.css*
+* A "reset" stylesheet, *akhet_demo/static/stylesheets/reset.css*
The HTML files are Mako templates. The stylesheets are static files.
index.html
----------
-This is a page template, so it contains the specific text for this page. It
-contains just the HTML body, not the tags around it or the HTML header. Those
-will be added by the site template. The first three lines are Mako constructs:
+This is a page template, so it contains only the unique parts of this page. The
+first three lines are Mako constructs:
.. code-block:: mako
:linenos:
<%inherit file="/site.html" />
- <%def name="title()">${project}</%def>
- <%def name="body_title()">Hello, ${project}!</%def>
+ <%def name="title()">Hello, ${project}!</%def>
+ <%def name="ht_title()">${project}</%def>
Line 1 makes the template inherit from the site template, which will add the
-surrounding HTML tags.
+site's header and footer. Lines 2 and 3 are Mako methods. They output the body
+title and the head title respectively.
-Lines 2 and 3 are Mako methods; they return values which will be used by
-the site template. Line 2 is the title for the "<title>" tag. Line 3 is the
-title to display inside the page. 'project' is a variable the view method
-passes via its return dict. The rest of the page is ordinary HTML so we
-won't bother showing it.
+The "${varname}" syntax is a placeholder which will output the named variable.
+Template variables can come from several sources: (1) keys in the view's return
+dict, (2) template globals specified in *akhet_demo/subscribers.py*, (3) local
+variables defined in the template, (4) built-in Mako variables like ``self``.
+
+The rest of the file is a big chunk of HTML that will be plugged into the site
+template. Mako implicitly puts this chunk in a method named "body", which can
+be called from other templates as we'll see in a moment.
Site template
-------------
-The site template contains everything around the page content: the "<html>"
-container tag, the HTML header, and the parts of the page body that are the
-same on every page. The most important construct here is the "${self.body()}"
-placeholder, which is where the entire page template will be rendered. Mako's
-'self' construct chooses the highest-level variable available, which allows a
-page template to override a default value in a parent template the way Python
-class attributes override superclass attributes.
-
-The "<head>" section contains the usual title, character set, stylesheet, and
-the like. You can modify these as you wish.
-
-The "<body>" section contains a standardized header and footer; you can modify
-these as you wish to put the same doodads on all your pages.
-
-Three "<%def>" methods are defined at the bottom of the file, which page
-templates can override:
-
-.. method:: head_extra()
-
- Override this to put extra tags into the <head> section like page-specific
- styles, Javascript, or metadata. The default is empty.
-
-.. method:: title()
-
- We saw this in the page template. Put the title for the <title> tag here.
- The default is empty: no title.
-
-.. method:: body_title()
-
- Put the title for the page body here. The default is to be the same as
- ``title``. You can override it if you want different wording, or to put
- embedded HTML tags in the body title. (The <title> can't have embedded HTML
- tags: the browser would display them literally.)
-
-The site template also has a stanza to display flash messages:
+The site template contains the "complete" HTML document, with
+placeholders to plug in content from the page template. The most important
+placeholder here is "${self.body()}", which outputs the body of the
+highest-level template in the inheritance chain.
+
+The template also calls "self.title()" and "self.ht_title()", and defines
+default implementations for these methods. The default body title is blank; the
+default head title is whatever the body title returns. So you can just set
+"title" in your pages and forget about "ht_title" if you want. Sometimes you'll
+have to make them different, however: (1) The head title can't contain HTML
+tags like <em> -- it will display them literally rather than changing the font.
+(2) Sometimes the body title is too wordy for the head title. (3) Many sites
+want the site name in the head title. A general rule of thumb for the head
+title is something like "Page Title &mdash; Site Name". Search engines rank the
+head title highly, so it should contain all the essential words that describe
+the page, and it should be less than sixty or so characters long so it fits on
+one line.
+
+There's one more method in the site template, "head_extra". It also is blank by
+default, but page templates can override it to add additional tags in the head.
+
+The other kind of placeholder in the site template is "${url.app}", which is
+used to form static URLs like "${url.app}/stylesheets.default.css". "url" is
+the URL generator, which the subscriber puts into the template namespace.
+"url.app" is the application's URL prefix. This is normally empty for a
+top-level application mounted at "/". But if the application is mounted at a
+sub-URL like "/site1", that will be what "url.app" is set to.
+
+Normally you'd generate URLs by route name, such as "${url('home')}" or its
+full form "${url.route('home')}". But static URLs don't have a route name. If
+we were using Pyramid's static view there would be another way to generate
+them, but the demo uses the static route so it can't do that. So we're left
+with literal URLs relative to the application prefix.
+
+The template displays flash messages, which a view may have pushed into the
+session before redirecting. The code for this is:
.. code-block:: mako
- <div id="content">
- <div id="flash-messages">
- % for message in request.session.pop_flash():
- <div class="info">${message}</div>
- % endfor
- </div>
-
-Flash messages are a queue of messages in the session which are displayed on
-the next page rendered. Normally a view will push a success or failure message
-and redirect, and the redirected-to page will display the message. If you call
-'pop_flash' without a queue name, the default queue is used. This is enough for
-many programs. You can also define multiple queues for different kinds of
-messages, and then pop each queue separately and display it in a different way.
-For instance:
+ <div id="content">
+ <div id="flash-messages">
+ % for message in request.session.pop_flash():
+ <div class="info">${message}</div>
+ % endfor
+ </div>
-.. code-block:: mako
+The stylesheet displays it all pretty-like.
- % for message in request.session.pop_flash("error"):
- <div class="error">${message}</div>
- % endfor
- % for message in request.session.pop_flash("warn"):
- <div class="error">${warning}</div>
- % endfor
Reset stylesheet
----------------
@@ -111,9 +102,9 @@ some overrides. Meyers does remove some attributes which have generally
been assumed to be intrinsic to the tag, such as margins around <p> and <h\*>.
His reasoning is that you should start with nothing and consciously re-add the
styles you want. Some people may find this attitude to be overkill. The reset
-stylesheet is just provided as a service if you want to use it. In any case, we
-re-add some expected styles, and I also set <dt> to bold which is a pet peeve
-of mine.
+stylesheet is just provided as a service if you want to use it. In any case, I
+have re-added some expected styles, and also set <dt> to boldface which is a
+pet peeve of mine.
If you want something with more bells and whistles, some Pyramid developers
recommend `HTML5 Boilerplate`_.
@@ -129,5 +120,5 @@ stylesheet. It defines some styles the default home page needs. You'll probably
want to adjust them for your layout.
The bottom section has styles for flash messages. The ".info" stanza is used by
-the default application. The ".warning" and ".error" styles are not used by
-default but are provided as extras.
+the demo. The ".warning" and ".error" styles are not used by
+the demo but are provided as extras.
287 docs/demo/details.rst
View
@@ -1,37 +1,66 @@
Details
-%%%%%%%%%%%%
+%%%%%%%
-pyramid.includes = pyramid_debugtoolbar
-mako.directories = akhet_demo:templates
+development.ini
+===============
-# Beaker cache
-cache.regions = default_term, second, short_term, long_term
-cache.type = memory
-cache.second.expire = 1
-cache.short_term.expire = 60
-cache.default_term.expire = 300
-cache.long_term.expire = 3600
+The config file contains the following settings which aren't in Pyramid's
+built-in scaffolds:
-# Beaker sessions
-#session.type = file
-#session.data_dir = %(here)s/data/sessions/data
-#session.lock_dir = %(here)s/data/sessions/lock
-session.type = memory
-session.key = akhet_demo
-session.secret = 0cb243f53ad865a0f70099c0414ffe9cfcfe03ac
+.. code-block:: ini
+ mako.directories = akhet_demo:templates
+ # Beaker cache
+ cache.regions = default_term, second, short_term, long_term
+ cache.type = memory
+ cache.second.expire = 1
+ cache.short_term.expire = 60
+ cache.default_term.expire = 300
+ cache.long_term.expire = 3600
+
+ # Beaker sessions
+ #session.type = file
+ #session.data_dir = %(here)s/data/sessions/data
+ #session.lock_dir = %(here)s/data/sessions/lock
+ session.type = memory
+ session.key = akhet_demo
+ session.secret = 0cb243f53ad865a0f70099c0414ffe9cfcfe03ac
+
+The "mako.includes" setting is necessary to set Mako's search path. You can add
+other Mako options here if you wish.
+
+The "cache." settings initialize Beaker caching. This is not actually necessary
+because the demo never uses a cache, but it's here for demonstration.
+
+The "session." settings initialize Beaker sessions. This is necessary if you
+use sessions or flash messages. Beaker supports several forms of session
+persistence: in-memory, files, memcached, database, etc. This configuration
+uses memory mode, which holds the sessions in memory until the application
+quits; it obviously works only with multi-threaded servers and not with than
+multi-process serviers. The default Pylons mode is file-based sessions, which
+is commented here. Recent recommendations suggest memcached is the most robust
+mode because it can scale to multiple servers; you can set that option if you
+wish.
+
+If you copy the session configuration to your application, do change
+"session.secret" to a random string. This is used to help ensure the integrity
+of the session, to prevent people from hijacking it.
Init module and main function
=============================
-::
+Almost all of the *akhet_demo/__init__.py* module is unique to the demo, so
+we'll just show the whole thing here:
+
+.. code-block:: python
+ :linenos:
from pyramid.config import Configurator
import pyramid_beaker
- def main(global_config, **settings):
+ def main(global_config, XXsettings):
""" This function returns a Pyramid WSGI application.
"""
config = Configurator(settings=settings)
@@ -54,9 +83,79 @@ Init module and main function
return config.make_wsgi_app()
+(Note: "\*\*settings" is shown as "XXsettings" because vim's syntax
+highlighting gets into a fit otherwise and mishighlights up the doc source file.)
+
+As you see, it activates Beaker sessions and caching, and sets up templates,
+subscribers, routes, and a static route. The Beaker setup passes the
+``settings`` dict to Beaker; that's how your settings are read. Pyramid
+cofigures Mako the same way behind the scenes, passing the settings to it.
+The "add_renderer" line tells Pyramid to recognize filenames ending in ".html"
+as Mako templates. The subscribers include we'll see in a minute.
+
+The static route has an include line and an "add_static_route" call.
+
+
+Helpers
+=======
+
+*akhet_demo/lib/helpers.py* is unique to the demo. It's a Pylons-like helpers
+module where you can put utility functions for your templates. The minimal
+WebHelpers imports for HTML tag helpers are there, but commented. I'm tempted
+to actually use the tag helpers in the site template but haven't done so yet.
+
+Most of WebHelpers works with Pyramid, including the popular
+``webhelpers.html`` subpackage, ``webhelpers.text``, and ``webhelpers.number``.
+Pyramid does not depend on WebHelpers so you'll have to add the dependency to
+your application if you want to use it. The only part that doesn't work with
+Pyramid is the ``webhelpers.pylonslib`` subpackage, which depends on Pylons'
+special globals.
+
+WebHelpers 1.3 has some new URL generator classes to make it easier to use
+with Pyramid. See the ``webhelpers.paginate`` documentation for details. (Note:
+this is *not* the same as Akhet's URL generator; it's a different kind of class
+specifically for the paginator's needs.)
+
+
+Subscribers
+===========
+
+*akhet_demo/subscribers.py* is unique to the demo. It sets up a URL generator
+and configures several Pylons-like globals for the template namespace. The only
+thing you need in here is the includeme function, which the application's main
+function invokes via the ``config.include(".subscribers")`` line.
+
+The ``add_renderer_globals`` subscriber configures the following variables for
+the template namespace:
+
+* ``h``: the helpers module.
+* ``r``: an alias for ``request``.
+* ``url``: the URL generator.
+
+It has commented code to configure "settings", "session", and "c" variables if
+you want those.
+
+For completeness, here are the system variables Pyramid 1.3 adds to the
+template namespace:
+
+* ``context``: the context.
+* ``renderer_name``: the name of the renderer.
+* ``renderer_info``: a ``RendererHelper`` object (defined in ``pyramid.renderers``).
+* ``request``: the request.
+* ``view``: the view. (A function or instance.)
+
+As a reminder, everything here is local to the current request. The URL
+generator is attached to the request object, and the renderer globals are set
+just before the renderer is invoked. These variables are all discarded at the
+end of the request.
+
Views
-=============
+=====
+
+The views module has a base class called ``Handler`` (but it's not related to
+"pyramid_handlers"). The index view demonstrates logging, optionally sets a
+flash message, and invokes a Mako template renderer.
::
@@ -91,154 +190,6 @@ Views
-Templates
-=========
-
-.html
-site template
-h, url, view
-stylesheet, reset stylesheet
-
-
-Site template
--------------
-
-Most applications using Mako will define a site template something like this:
-
-.. code-block:: mako
-
- <!DOCTYPE html>
- <html>
- <head>
- <title>${self.title()}</title>
- <link rel="stylesheet" href="${application_url}/default.css"
- type="text/css" />
- </head>
- <body>
-
- <!-- *** BEGIN page content *** -->
- ${self.body()}
- <!-- *** END page content *** -->
- </body>
- </html>
- <%def name="title()" />
-
-Then the page templates can inherit it like so:
-
-.. code-block:: mako
-
- <%inherit file="/site.html" />
- <%def name="title()">My Title</def>
- ... rest of page content goes here ...
-
-Static files
-============
-
-Pyramid has five ways to serve static files. Each way has different
-advantages and limitations, and requires a different way to generate static
-URLs.
-
-``config.add_static_route``
-
- This is the Akhet default,
- and is closest to Pylons. It serves the static directory as an overlay on
- "/", so that URL "/robots.txt" serves "zzz/static/robots.txt", and URL
- "/images/logo.png" serves "zzz/static/images/logo.png". If the file does
- not exist, the route will not match the URL and Pyramid will try the next
- route or traversal. You cannot use any of the URL generation methods with
- this; instead you can put a literal URL like
- "${application_url}/images/logo.png" in your template.
-
- Usage::
-
- config.include('akhet')
- config.add_static_route('zzz', 'static', cache_max_age=3600)
- # Arg 1 is the Python package containing the static files.
- # Arg 2 is the subdirectory in the package containing the files.
-
-
-Session, flash messages, and secure forms
-=========================================
-
-Pyramid's session object is ``request.session``. It has its own interface but
-uses Beaker on the back end, and is configured in the INI file the same way as
-Pylons' session. It's a dict-like object and can store any pickleable value.
-It's pulled from persistent storage only if it's accessed during the request
-processing, and it's (re)saved only if the data changes.
-
-Unlike Pylons' sesions, you don't have to call ``session.save()`` after adding
-or replacing keys because Pyramid does that for you. But you do have to call
-``session.changed()`` if you modify a mutable value in place (e.g., a session
-value that's a list or dict) because Pyramid can't tell that child objects have
-been modified.
-
-You can call ``session.invalidate()`` to discard the session data at the end of
-the request. ``session.created`` is an integer timestamp in Unix ticks telling
-when the session was created, and ``session.new`` is true if it was created
-during this request (as opposed to being loaded from persistent storage).
-
-Pyramid sessions have two extra features: flash messages and a secure form
-token. These replace ``webhelpers.pylonslib.flash`` and
-``webhelpers.pylonslib.secure_form``, which are incompatible with Pyramid.
-
-Flash messages are a session-based queue. You can push a message to be
-displayed on the next request, such as before redirecting. This is often used
-after form submissions, to push a success or failure message before redirecting
-to the record's main screen. (This is different from form validation, which
-normally redisplays the form with error messages if the data is rejected.)
-
-To push a message, call ``request.session.flash("My message.")`` The message is
-normally text but it can be any object. Your site template will then have to
-call ``request.session.pop_flash()`` to retrieve the list of messages, and
-display then as it wishes, perhaps in <div>'s or a <ul>. The queue is
-automatically cleared when the messages are popped, to ensure they are
-displayed only once.
-
-The full signature for the flash method is::
-
- session.flash(message, queue='', allow_duplicate=True)
-
-You can have as many message queues as you wish, each with a different string
-name. You can use this to display warnings differently from errors, or to show
-different kinds of messages at different places on the page. If
-``allow_duplicate`` is false, the message will not be inserted if an identical
-message already exists in that queue. The ``session.pop_flash`` method also takes a
-queue argument to specify a queue. You can also use ``session.peek_flash`` to
-look at the messages without deleting them from the queue.
-
-The secure form token prevents cross-site request forgery (CSRF)
-attacts. Call ``session.get_csrf_token()`` to get the session's token, which is
-a random string. (The first time it's called, it will create a new random token and
-store it in the session. Thereafter it will return the same token.) Put the
-token in a hidden form field. When the form submission comes back in the next
-request, call ``session.get_csrf_token()`` again and compare it to the hidden
-field's value; they should be the same. If the form data is missing the field
-or the value is different, reject the request, perhaps by returning a forbidden
-status. ``session.new_csrf_token()`` always returns a new token, overwriting
-the previous one if it exists.
-
-WebHelpers and forms
-====================
-
-Most of WebHelpers works with Pyramid, including the popular
-``webhelpers.html`` subpackage, ``webhelpers.text``, and ``webhelpers.number``.
-Pyramid does not depend on WebHelpers so you'll have to add the dependency to
-your application if you want to use it. The only part that doesn't work with
-Pyramid is the ``webhelpers.pylonslib`` subpackage, which depends on Pylons'
-special globals.
-
-We are working on a form demo that compares various form libraries: Deform,
-Formish, FormEncode/htmlfill.
-
-To organize the form display-validate-action route, we recommend the
-``pyramid_simpleform`` package. It replaces ``@validate`` in Pylons. It's not a
-decorator because too many people found the decorator too inflexible: they
-ended up copying part of the code into their action method.
-
-WebHelpers 1.3 has some new URL generator classes to make it easier to use
-with Pyramid. See the ``webhelpers.paginate`` documentation for details. (Note:
-this is *not* the same as Akhet's URL generator; it's a different kind of class
-specifically for the paginator's needs.)
.. include:: ../links.rst
5 docs/demo/features.rst
View
@@ -18,9 +18,6 @@ repository like any Pyramid application:
(myenv)$ pip install -e .
(myenv)$ pserve development.ini
-Features
-========
-
The demo has the following features ported from the former 'akhet' scaffold
(which are not in the standard Pyramid scaffolds):
@@ -32,7 +29,7 @@ The demo has the following features ported from the former 'akhet' scaffold
generator 'url', and instructions for adding additional ones.
* Serve static files at any URL, without being limited by URL prefixes.
* Listen on localhost:5000 by defalt.
-* Session configuration.
+* Beaker session and cache configuration.
* Demonstration of flash messages and logging.
Please sign in to comment.
Something went wrong with that request. Please try again.