summaryrefslogtreecommitdiff
path: root/docs/tutorials/wiki2/basiclayout.rst
blob: 2d25ace002071ab7f165026a48d4097c3b973bde (plain)
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
============
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 :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/
<http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/basiclayout/>`_.

App Startup with ``__init__.py``
--------------------------------

A directory on disk can be turned into a Python :term:`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:

   .. 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:main]`` section.  This will be a URI (something like
``sqlite://``):

   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 6-9
      :linenos:
      :language: py

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 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 :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
      :language: py

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 :meth:`pyramid.config.Configurator.add_view` in :term:`URL dispatch` to
register views for the routes, mapping your patterns to code:

   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 14-15
      :language: py

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 :term:`renderer` will use this template to create a
response.

Finally, we use the :meth:`pyramid.config.Configurator.make_wsgi_app`
method to return a :term:`WSGI` application:

   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 16
      :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``
---------------------------------

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.

   .. literalinclude:: src/basiclayout/tutorial/models.py
      :end-before: DBSession
      :linenos:
      :language: py

Next we set up a SQLAlchemy "DBSession" object:

   .. literalinclude:: src/basiclayout/tutorial/models.py
      :lines: 15-16
      :linenos:
      :language: py

We also need to 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

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:

   .. 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