More documentation updates and tweaking.

This commit is contained in:
Ryan Petrello
2011-03-06 14:31:18 -05:00
parent 5e34617839
commit 615813486f
4 changed files with 62 additions and 62 deletions

View File

@@ -143,16 +143,3 @@ app is running I can access ``foo`` values like::
>>> conf.foo
Config({'bar': True, 'baz': False})
Files and Structure
===================
Pecan gives you a ``start.py`` file so you can manually run your application
from the command line. By default, this file requires a parameter which is
a configuration file without the ``.py`` extension.
If you have a configuration file named ``config.py`` you would need to pass it
to ``start.py`` like::
python start.py config

View File

@@ -1,25 +1,25 @@
.. _databases:
Working with Databases and ORM's
Working with Databases, Transactions, and ORM's
=============
Out of the box, Pecan provides no opinionated support for working with databases,
but it's easy to hook into your ORM of choice with minimal effort. This article
details best practices for integration the popular Python ORM, SQLAlchemy, into
details best practices for integrating the popular Python ORM, SQLAlchemy, into
your Pecan project.
init_model and Preparing Your Model
``init_model`` and Preparing Your Model
----------------
Pecan's default quickstart project includes an empty stub directory for implementing
your model as you see fit::
.
└── test_project
├── app.py
├── __init__.py
├── controllers
├── model
│   ├── __init__.py
└── templates
.
└── test_project
├── app.py
├── __init__.py
├── controllers
├── model
│   ├── __init__.py
└── templates
By default, this module contains a special method, ``init_model``::
@@ -90,10 +90,14 @@ Binding Within the Application
----------------
There are several approaches that can be taken to wrap your application's requests with calls
to appropriate model function calls. One approach is WSGI middleware. We also recommend
Pecan hooks (see ref:`hooks`). Pecan comes with ``TransactionHook``, a hook which can
be used to wrap requests in transactions for you. To use it, you simply include it in your
Pecan :ref:`hooks`. Pecan comes with ``TransactionHook``, a hook which can
be used to wrap requests in transactions for you. To use it, simply include it in your
project's ``app.py`` file and pass it a set of functions related to database binding::
from pecan import conf, make_app
from pecan.hooks import TransactionHook
from test_project import model
app = make_app(
conf.app.root,
static_root = conf.app.static_root,
@@ -111,28 +115,30 @@ project's ``app.py`` file and pass it a set of functions related to database bin
)
For the above example, on HTTP POST, PUT, and DELETE requests, ``TransactionHook`` behaves in the
following manner::
following manner:
#. Before controller routing has been determined, ``model.start()`` is called. This function should bind to the appropriate SQLAlchemy engine and start a transaction.
#. Before controller routing has been determined, ``model.start()`` is called. This function
should bind to the appropriate SQLAlchemy engine and start a transaction.
#. Controller code is run and returns.
#. If your controller or template rendering fails and raises an exception, ``model.rollback()``
is called and the original exception is re-raised. This allows you to rollback your database
transaction to avoid committing work when exceptions occur in your application code.
#. If your controller or template rendering fails and raises an exception, ``model.rollback()`` is called and the original exception is re-raised. This allows you to rollback your database transaction to avoid committing work when exceptions occur in your application code.
#. If the controller returns successfully, ``model.commit()`` and ``model.clear()`` are called.
On idempotent operations (like HTTP GET and HEAD requests), TransactionHook behaves in the following
manner::
manner:
#. ``model.start_read_only()`` is called. This function should bind to your SQLAlchemy engine.
#. Controller code is run and returns.
#. If the controller returns successfully, ``model.clear()`` is called.
Splitting Reads and Writes
----------------
Employing the above strategy with ``TransactionHook`` makes it very simple to split database
reads and writes based upon HTTP methods (i.e., GET/HEAD requests are read and would potentially
Employing the strategy above with ``TransactionHook`` makes it very simple to split database
reads and writes based upon HTTP methods (i.e., GET/HEAD requests are read-only and would potentially
be routed to a read-only database slave, while POST/PUT/DELETE requests require writing, and
would bind to a master database with read/write priveleges) It's also very easy extend
would always bind to a master database with read/write privileges). It's also very easy to extend
``TransactionHook`` or write your own hook implementation for more refined control over where and
when database bindings are called.

View File

@@ -9,7 +9,7 @@ There is nothing wrong with WSGI Middleware, and actually, it is really easy to
use middleware with Pecan, but it can be hard (sometimes impossible) to have
access to Pecan's internals from within middleware. Hooks make this easier.
Hooks offer four ways of dealing with a request:
Hooks allow you to execute code at key points throughout the life cycle of your request:
* ``on_route``: called before Pecan attempts to route a request to a controller
@@ -22,21 +22,27 @@ Hooks offer four ways of dealing with a request:
Implementation
--------------
In the below example, we will write a simple hook that will gather
some information about the request and print it out to ``stdout``.
some information about the request and print it to ``stdout``.
Your hook implementation needs to import ``PecanHook`` so it can be used as a base class::
Your hook implementation needs to import ``PecanHook`` so it can be used as a base class.
From there, you'll need to override the ``on_route``, ``before``, ``after``, or ``on_error`` methods::
from pecan.hooks import PecanHook
class SimpleHook(PecanHook):
def before(self, state):
print "\nabout to enter the controller..."
def after(self, state):
print "\nmethod: \t %s" % state.request.method
print "\nresponse: \t %s" % state.response.status
``on_route``, ``before``, and ``after`` are passed a shared state object which includes useful
``on_route``, ``before``, and ``after`` are each passed a shared state object which includes useful
information about the request, such as the request and response object, and which controller
was chosen by Pecan's routing.
``on_error`` is passed a shared state object **and** the original exception.
Attaching Hooks
--------------
@@ -63,16 +69,17 @@ using the ``__hooks__`` attribute on one or more controllers::
@expose('json')
def index(self):
print "DO SOMETHING!"
return dict()
Running it
----------
Now that our ``SimpleHook`` is included, let's see what happens when we run
the app and browse the application::
the app and browse the application from our web browser::
pecan serve config.py
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
about to enter the controller...
DO SOMETHING!
method: GET
response: 200 OK

View File

@@ -9,7 +9,7 @@ error handling activities, like:
* Transforming strings from form submissions into useful Python objects.
* Simplifying the process of re-displaying form values and associated error messages inline.
Rather than re-inventing the wheel, Pecan uses FormEncode for schemas and form validation.
Rather than re-inventing the wheel, Pecan uses `FormEncode <http://formencode.org/>`_ for schemas and form validation.
Writing and Applying Schemas
------------------------------
@@ -37,7 +37,7 @@ Pecan's ``expose`` decorator::
Validating JSON Content
------------------------------
In addition to simple form arguments, Pecan also makes it easy to validate JSON request bodies.
Often, especially in AJAX requests, the request content is encoded as a JSON in the request body.
Often, especially in AJAX requests, the request content is encoded as JSON in the request body.
Pecan's validation can handle the decoding for you and apply schema validation to the decoded
data structure::
@@ -94,7 +94,6 @@ This is especially useful when used in combination with generic
controller methods::
from pecan import request, expose
from formencode import Schema, validators as v
class ProfileSchema(Schema):
@@ -121,7 +120,8 @@ controller methods::
"""
This method will do something with POST arguments.
If the schema validation fails, an internal redirect will
cause the `profile.html` template to be rendered.
cause the `profile.html` template to be rendered via the
``index_get`` method.
"""
name = kw.get('name')
@@ -133,27 +133,27 @@ In this example, when form validation errors occur (for example, the email provi
Pecan will handle pre-filling the form values in ``profile.html`` for you. Additionally, inline
errors will be appended to the template using FormEncode's ``htmlfill``.
Bypassing htmlfill
Bypassing ``htmlfill``
------------------------------
Sometimes you want certain fields in your templates to be ignored (i.e., not pre-filled) by htmlfill.
Sometimes you want certain fields in your templates to be ignored (i.e., not pre-filled) by ``htmlfill``.
A perfect use case for this is password and hidden input fields. The default Pecan template namespace
includes a built-in function, ``static``, which allows you to enforce a static value for form fields,
preventing htmlfill from filling it in form arguments::
preventing ``htmlfill`` from filling in submitted form variables::
<form method="POST">
<dl>
<dt>Username:</dt>
<dd><input type="text" name="username" /></dd>
<dt>Password:</dt>
<dd><input type="password" name="password" value="${static('password', '')}" /></dd>
<input type="hidden" name="ticket" value="${static('ticket', 'RANDOM_PER_REQUEST_VALUE')}" />
</dl>
<button>Login</button>
</form>
<form method="POST">
<dl>
<dt>Username:</dt>
<dd><input type="text" name="username" /></dd>
<dt>Password:</dt>
<dd><input type="password" name="password" value="${static('password', '')}" /></dd>
<input type="hidden" name="ticket" value="${static('ticket', 'RANDOM_PER_REQUEST_VALUE')}" />
</dl>
<button>Login</button>
</form>
Working with variabledecode
Working with ``variabledecode``
------------------------------
Pecan also lets you take advantage of FormEncode's variabledecode for transforming flat HTML form
Pecan also lets you take advantage of FormEncode's ``variabledecode`` for transforming flat HTML form
submissions into nested structures::
from pecan import expose