Basic Layout¶
The starter files generated by the pyramid_routesalchemy
scaffold are
basic, but they provide a good orientation for the high-level patterns common
to most url dispatch -based Pyramid projects.
The source code for this tutorial stage can be browsed at http://github.com/Pylons/pyramid/tree/1.2-branch/docs/tutorials/wiki2/src/basiclayout/.
App Startup with __init__.py
¶
A directory on disk can be turned into a Python package by containing
an __init__.py
file. Even if empty, this marks a directory as a Python
package. We use __init__.py
both as a package marker and to contain
configuration code.
The generated development.ini
file is read by paster
which looks for
the application module in the use
variable of the app:main
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 a function named
main
.
First we need some imports to support later code:
1 2 3 4 5 from pyramid.config import Configurator from sqlalchemy import engine_from_config from tutorial.models import initialize_sql
Next we define the main function and create a SQLAlchemy database engine from
the sqlalchemy.
prefixed settings in the development.ini
file’s
[app:main]
section. This will be a URI (something like
sqlite://
):
1 2 3 4 def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.')
We then initialize our SQL database using SQLAlchemy, passing it the engine:
initialize_sql(engine)
The next step is to construct a Configurator:
config = Configurator(settings=settings)
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 pyramid.reload_templates
,
db_string
, etc.
We now can call pyramid.config.Configurator.add_static_view()
with the
arguments static
(the name), and tutorial:static
(the path):
config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
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 route configuration
via the pyramid.config.Configurator.add_route()
method that will be
used when the URL is /
:
config.add_route('home', '/')
Since this route has a pattern
equalling /
it is the route that will
be matched when the URL /
is visted, e.g. http://localhost:6543/
.
Mapping the home
route to code is done by registering a view. You will
use pyramid.config.Configurator.add_view()
in URL dispatch to
register views for the routes, mapping your patterns to code:
config.add_view('tutorial.views.my_view', route_name='home', renderer='templates/mytemplate.pt')
The first positional add_view
argument tutorial.views.my_view
is the
dotted name to a function we write (generated by the
pyramid_routesalchemy
scaffold) that is given a request
object and
which returns a response or a dictionary. This view also names a
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 renderer will use this template to create a
response.
Finally, we use the pyramid.config.Configurator.make_wsgi_app()
method to return a WSGI application:
return config.make_wsgi_app()
Our final __init__.py
file will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pyramid.config import Configurator from sqlalchemy import engine_from_config from tutorial.models import initialize_sql def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') initialize_sql(engine) config = Configurator(settings=settings) config.add_static_view('static', 'tutorial:static', cache_max_age=3600) config.add_route('home', '/') config.add_view('tutorial.views.my_view', route_name='home', renderer='templates/mytemplate.pt') return config.make_wsgi_app()
Content Models with models.py
¶
In a SQLAlchemy-based application, a model object is an object
composed by querying the SQL database which backs an application.
SQLAlchemy is an “object relational mapper” (an ORM). The
models.py
file is where the pyramid_routesalchemy
scaffold
put the classes that implement our models.
Let’s take a look. First, we need some imports to support later code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import transaction from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import Unicode from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker from zope.sqlalchemy import ZopeTransactionExtension
Next we set up a SQLAlchemy “DBSession” object:
1 2 DBSession = scoped_session(sessionmaker( extension=ZopeTransactionExtension()))
We also need to create a declarative Base
object to use as a
base class for our model:
Base = declarative_base()
To give a simple example of a model class, we define one named MyModel
:
1 2 3 4 5 6 7 8 9 class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Unicode(255), unique=True) value = Column(Integer) def __init__(self, name, value): self.name = name self.value = value
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:
1 2 3 4 5 6 def populate(): session = DBSession() model = MyModel(name=u'root',value=55) session.add(model) session.flush() transaction.commit()
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.
1 2 3 4 5 6 7 8 def initialize_sql(engine): DBSession.configure(bind=engine) Base.metadata.bind = engine Base.metadata.create_all(engine) try: populate() except IntegrityError: transaction.abort()
Here is the complete source for models.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import transaction from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import Unicode from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker from zope.sqlalchemy import ZopeTransactionExtension DBSession = scoped_session(sessionmaker( extension=ZopeTransactionExtension())) Base = declarative_base() class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Unicode(255), unique=True) value = Column(Integer) def __init__(self, name, value): self.name = name self.value = value def populate(): session = DBSession() model = MyModel(name=u'root',value=55) session.add(model) session.flush() transaction.commit() def initialize_sql(engine): DBSession.configure(bind=engine) Base.metadata.bind = engine Base.metadata.create_all(engine) try: populate() except IntegrityError: transaction.abort()