Steve Piercy
2017-06-11 65a6d3a79f8fdcdd32a70888c669a8548366f7cb
commit | author | age
da42d5 1
49d634 2 .. _quick_tour:
PE 3
ae9014 4 =====================
PE 5 Quick Tour of Pyramid
6 =====================
5b47ba 7
9b7f4d 8 Pyramid lets you start small and finish big.  This *Quick Tour* of Pyramid is
257ac0 9 for those who want to evaluate Pyramid, whether you are new to Python web
SP 10 frameworks, or a pro in a hurry. For more detailed treatment of each topic,
11 give the :ref:`quick_tutorial` a try.
12
9b7f4d 13
b731b5 14 Installation
71b83e 15 ============
83fefb 16
257ac0 17 Once you have a standard Python environment setup, getting started with Pyramid
SP 18 is a breeze. Unfortunately "standard" is not so simple in Python. For this
556258 19 Quick Tour, it means `Python <https://www.python.org/downloads/>`_, `venv
SP 20 <https://packaging.python.org/en/latest/projects/#venv>`_ (or `virtualenv for
21 Python 2.7 <https://packaging.python.org/en/latest/projects/#virtualenv>`_),
22 `pip <https://packaging.python.org/en/latest/projects/#pip>`_, and `setuptools
23 <https://packaging.python.org/en/latest/projects/#easy-install>`_.
9b7f4d 24
ebbe68 25 To save a little bit of typing and to be certain that we use the modules,
SP 26 scripts, and packages installed in our virtual environment, we'll set an
27 environment variable, too.
28
c8a5e0 29 As an example, for Python 3.6+ on Linux:
83fefb 30
ebca90 31 .. parsed-literal::
83fefb 32
ebbe68 33     # set an environment variable to where you want your virtual environment
SP 34     $ export VENV=~/env
35     # create the virtual environment
36     $ python3 -m venv $VENV
37     # install pyramid
38     $ $VENV/bin/pip install pyramid
556258 39     # or for a specific released version
ebbe68 40     $ $VENV/bin/pip install "pyramid==\ |release|\ "
83fefb 41
b731b5 42 For Windows:
9b7f4d 43
ebca90 44 .. parsed-literal::
9b7f4d 45
ebbe68 46     # set an environment variable to where you want your virtual environment
108121 47     c:\\> set VENV=c:\\env
ebbe68 48     # create the virtual environment
b730ae 49     c:\\> python -m venv %VENV%
ebbe68 50     # install pyramid
SP 51     c:\\> %VENV%\\Scripts\\pip install pyramid
556258 52     # or for a specific released version
ebbe68 53     c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ "
9b7f4d 54
bdd544 55 Of course Pyramid runs fine on Python 2.7+, as do the examples in this *Quick
ebbe68 56 Tour*. We're showing Python 3 for simplicity. (Pyramid had production support
SP 57 for Python 3 in October 2011.) Also for simplicity, the remaining examples will
58 show only UNIX commands.
bf84d9 59
2033ee 60 .. seealso:: See also:
b731b5 61     :ref:`Quick Tutorial section on Requirements <qtut_requirements>`,
21f2b6 62     :ref:`installing_unix`, :ref:`Before You Install <installing_chapter>`,
SP 63     :ref:`Why use $VENV/bin/pip instead of source bin/activate, then pip
64     <venv-bin-pip-vs-source-bin-activate>`, and
257ac0 65     :ref:`Installing Pyramid on a Windows System <installing_windows>`.
SP 66
71b83e 67
PE 68 Hello World
69 ===========
47eaa1 70
257ac0 71 Microframeworks have shown that learning starts best from a very small first
SP 72 step. Here's a tiny application in Pyramid:
47eaa1 73
ae9014 74 .. literalinclude:: quick_tour/hello_world/app.py
71b83e 75     :linenos:
da42d5 76     :language: python
47eaa1 77
PE 78 This simple example is easy to run. Save this as ``app.py`` and run it:
79
80 .. code-block:: bash
81
ebbe68 82     $ $VENV/bin/python ./app.py
47eaa1 83
1273d0 84 Next open http://localhost:6543/ in a browser, and you will see the ``Hello
SP 85 World!`` message.
47eaa1 86
58febc 87 New to Python web programming? If so, some lines in the module merit
71b83e 88 explanation:
47eaa1 89
257ac0 90 #. *Line 10*. ``if __name__ == '__main__':`` is Python's way of saying "Start
SP 91    here when running from the command line".
47eaa1 92
257ac0 93 #. *Lines 11-13*. Use Pyramid's :term:`configurator` to connect :term:`view`
SP 94    code to a particular URL :term:`route`.
47eaa1 95
257ac0 96 #. *Lines 6-7*. Implement the view code that generates the :term:`response`.
47eaa1 97
71b83e 98 #. *Lines 14-16*. Publish a :term:`WSGI` app using an HTTP server.
47eaa1 99
257ac0 100 As shown in this example, the :term:`configurator` plays a central role in
SP 101 Pyramid development. Building an application from loosely-coupled parts via
102 :doc:`../narr/configuration` is a central idea in Pyramid, one that we will
103 revisit regurlarly in this *Quick Tour*.
d559af 104
2033ee 105 .. seealso:: See also:
b731b5 106    :ref:`Quick Tutorial Hello World <qtut_hello_world>`,
257ac0 107    :ref:`firstapp_chapter`, and :ref:`Todo List Application in One File
SP 108    <cookbook:single-file-tutorial>`.
109
5b47ba 110
1273d0 111 Handling web requests and responses
d559af 112 ===================================
47eaa1 113
257ac0 114 Developing for the web means processing web requests. As this is a critical
SP 115 part of a web application, web developers need a robust, mature set of software
116 for web requests.
47eaa1 117
257ac0 118 Pyramid has always fit nicely into the existing world of Python web development
d5b5d0 119 (virtual environments, packaging, cookiecutters, one of the first to embrace
257ac0 120 Python 3, etc.). Pyramid turned to the well-regarded :term:`WebOb` Python
SP 121 library for request and response handling. In our example above, Pyramid hands
122 ``hello_world`` a ``request`` that is :ref:`based on WebOb <webob_chapter>`.
47eaa1 123
71b83e 124 Let's see some features of requests and responses in action:
PE 125
ae9014 126 .. literalinclude:: quick_tour/requests/app.py
da42d5 127     :language: python
71b83e 128     :pyobject: hello_world
PE 129
257ac0 130 In this Pyramid view, we get the URL being visited from ``request.url``. Also
1273d0 131 if you visited http://localhost:6543/?name=alice in a browser, the name is
ebbe68 132 included in the body of the response:
SP 133
134 .. code-block:: text
71b83e 135
d559af 136   URL http://localhost:6543/?name=alice with name: alice
PE 137
257ac0 138 Finally we set the response's content type, and return the Response.
5b47ba 139
2033ee 140 .. seealso:: See also:
257ac0 141     :ref:`Quick Tutorial Request and Response <qtut_request_response>` and
SP 142     :ref:`webob_chapter`.
143
71b83e 144
PE 145 Views
146 =====
147
257ac0 148 For the examples above, the ``hello_world`` function is a "view". In Pyramid
SP 149 views are the primary way to accept web requests and return responses.
71b83e 150
d559af 151 So far our examples place everything in one file:
PE 152
153 - the view function
154
155 - its registration with the configurator
156
1273d0 157 - the route to map it to an URL
d559af 158
PE 159 - the WSGI application launcher
160
257ac0 161 Let's move the views out to their own ``views.py`` module and change the
SP 162 ``app.py`` to scan that module, looking for decorators that set up the views.
1273d0 163
257ac0 164 First our revised ``app.py``:
71b83e 165
ae9014 166 .. literalinclude:: quick_tour/views/app.py
da42d5 167     :language: python
71b83e 168     :linenos:
PE 169
257ac0 170 We added some more routes, but we also removed the view code. Our views and
SP 171 their registrations (via decorators) are now in a module ``views.py``, which is
172 scanned via ``config.scan('views')``.
71b83e 173
257ac0 174 We now have a ``views.py`` module that is focused on handling requests and
SP 175 responses:
71b83e 176
ae9014 177 .. literalinclude:: quick_tour/views/views.py
da42d5 178     :language: python
71b83e 179     :linenos:
PE 180
1273d0 181 We have four views, each leading to the other. If you start at
257ac0 182 http://localhost:6543/, you get a response with a link to the next view. The
SP 183 ``hello_view`` (available at the URL ``/howdy``) has a link to the
184 ``redirect_view``, which issues a redirect to the final view.
65d171 185
257ac0 186 Earlier we saw ``config.add_view`` as one way to configure a view. This section
SP 187 introduces ``@view_config``. Pyramid's configuration supports :term:`imperative
188 configuration`, such as the ``config.add_view`` in the previous example. You
189 can also use :term:`declarative configuration` in which a Python
190 :term:`decorator` is placed on the line above the view. Both approaches result
191 in the same final configuration, thus usually it is simply a matter of taste.
71b83e 192
2033ee 193 .. seealso:: See also:
257ac0 194    :ref:`Quick Tutorial Views <qtut_views>`, :doc:`../narr/views`,
SP 195    :doc:`../narr/viewconfig`, and :ref:`debugging_view_configuration`.
196
71b83e 197
d559af 198 Routing
PE 199 =======
71b83e 200
257ac0 201 Writing web applications usually means sophisticated URL design. We just saw
SP 202 some Pyramid machinery for requests and views. Let's look at features that help
203 with routing.
47eaa1 204
d559af 205 Above we saw the basics of routing URLs to views in Pyramid:
47eaa1 206
257ac0 207 - Your project's "setup" code registers a route name to be used when matching
SP 208   part of the URL.
47eaa1 209
257ac0 210 - Elsewhere a view is configured to be called for that route name.
47eaa1 211
d559af 212 .. note::
47eaa1 213
257ac0 214     Why do this twice? Other Python web frameworks let you create a route and
SP 215     associate it with a view in one step. As illustrated in
216     :ref:`routes_need_ordering`, multiple routes might match the same URL
217     pattern. Rather than provide ways to help guess, Pyramid lets you be
218     explicit in ordering. Pyramid also gives facilities to avoid the problem.
d559af 219
257ac0 220 What if we want part of the URL to be available as data in my view? We can use
SP 221 this route declaration, for example:
47eaa1 222
ae9014 223 .. literalinclude:: quick_tour/routing/app.py
da42d5 224     :language: python
257ac0 225     :linenos:
SP 226     :lines: 6
227     :lineno-start: 6
47eaa1 228
257ac0 229 With this, URLs such as ``/howdy/amy/smith`` will assign ``amy`` to ``first``
SP 230 and ``smith`` to ``last``. We can then use this data in our view:
47eaa1 231
ae9014 232 .. literalinclude:: quick_tour/routing/views.py
da42d5 233     :language: python
257ac0 234     :linenos:
SP 235     :lines: 5-8
236     :lineno-start: 5
237     :emphasize-lines: 3
47eaa1 238
257ac0 239 ``request.matchdict`` contains values from the URL that match the "replacement
SP 240 patterns" (the curly braces) in the route declaration. This information can
241 then be used in your view.
47eaa1 242
2033ee 243 .. seealso:: See also:
257ac0 244    :ref:`Quick Tutorial Routing <qtut_routing>`, :doc:`../narr/urldispatch`,
SP 245    :ref:`debug_routematch_section`, and :doc:`../narr/router`.
246
71b83e 247
d559af 248 Templating
PE 249 ==========
71b83e 250
257ac0 251 Ouch. We have been making our own ``Response`` and filling the response body
SP 252 with HTML. You usually won't embed an HTML string directly in Python, but
253 instead you will use a templating language.
47eaa1 254
257ac0 255 Pyramid doesn't mandate a particular database system, form library, and so on.
SP 256 It encourages replaceability. This applies equally to templating, which is
257 fortunate: developers have strong views about template languages. That said,
258 the Pylons Project officially supports bindings for Chameleon, Jinja2, and
259 Mako. In this step let's use Chameleon.
47eaa1 260
039d12 261 Let's add ``pyramid_chameleon``, a Pyramid :term:`add-on` which enables
257ac0 262 Chameleon as a :term:`renderer` in our Pyramid application:
561a7e 263
HH 264 .. code-block:: bash
265
ebbe68 266     $ $VENV/bin/pip install pyramid_chameleon
561a7e 267
257ac0 268 With the package installed, we can include the template bindings into our
SP 269 configuration in ``app.py``:
561a7e 270
257ac0 271 .. literalinclude:: quick_tour/templating/app.py
da42d5 272     :language: python
257ac0 273     :linenos:
SP 274     :lines: 6-8
275     :lineno-start: 6
276     :emphasize-lines: 2
561a7e 277
257ac0 278 Now lets change our ``views.py`` file:
561a7e 279
ae9014 280 .. literalinclude:: quick_tour/templating/views.py
da42d5 281     :language: python
257ac0 282     :linenos:
SP 283     :emphasize-lines: 4,6
d559af 284
257ac0 285 Ahh, that looks better. We have a view that is focused on Python code. Our
SP 286 ``@view_config`` decorator specifies a :term:`renderer` that points to our
287 template file. Our view then simply returns data which is then supplied to our
288 template ``hello_world.pt``:
d559af 289
ae9014 290 .. literalinclude:: quick_tour/templating/hello_world.pt
d559af 291     :language: html
PE 292
257ac0 293 Since our view returned ``dict(name=request.matchdict['name'])``, we can use
SP 294 ``name`` as a variable in our template via ``${name}``.
5b47ba 295
2033ee 296 .. seealso:: See also:
b731b5 297     :ref:`Quick Tutorial Templating <qtut_templating>`,
257ac0 298     :doc:`../narr/templates`, :ref:`debugging_templates`, and
SP 299     :ref:`available_template_system_bindings`.
d559af 300
PE 301
257ac0 302 Templating with Jinja2
SP 303 ======================
304
305 We just said Pyramid doesn't prefer one templating language over another. Time
306 to prove it. Jinja2 is a popular templating system, modeled after Django's
307 templates. Let's add ``pyramid_jinja2``, a Pyramid :term:`add-on` which enables
308 Jinja2 as a :term:`renderer` in our Pyramid applications:
47eaa1 309
PE 310 .. code-block:: bash
311
ebbe68 312     $ $VENV/bin/pip install pyramid_jinja2
47eaa1 313
257ac0 314 With the package installed, we can include the template bindings into our
SP 315 configuration:
47eaa1 316
257ac0 317 .. literalinclude:: quick_tour/jinja2/app.py
da42d5 318     :language: python
257ac0 319     :linenos:
SP 320     :lines: 6-8
321     :lineno-start: 6
322     :emphasize-lines: 2
47eaa1 323
58febc 324 The only change in our view is to point the renderer at the ``.jinja2`` file:
47eaa1 325
ae9014 326 .. literalinclude:: quick_tour/jinja2/views.py
da42d5 327     :language: python
257ac0 328     :linenos:
SP 329     :lines: 4-6
330     :lineno-start: 4
331     :emphasize-lines: 1
47eaa1 332
d559af 333 Our Jinja2 template is very similar to our previous template:
47eaa1 334
ae9014 335 .. literalinclude:: quick_tour/jinja2/hello_world.jinja2
ebca90 336     :language: html
47eaa1 337
d559af 338 Pyramid's templating add-ons register a new kind of renderer into your
257ac0 339 application. The renderer registration maps to different kinds of filename
SP 340 extensions. In this case, changing the extension from ``.pt`` to ``.jinja2``
341 passed the view response through the ``pyramid_jinja2`` renderer.
47eaa1 342
2033ee 343 .. seealso:: See also:
257ac0 344     :ref:`Quick Tutorial Jinja2 <qtut_jinja2>`, `Jinja2 homepage
SP 345     <http://jinja.pocoo.org/>`_, and :ref:`pyramid_jinja2 Overview
346     <jinja2:overview>`.
347
47eaa1 348
1273d0 349 Static assets
47eaa1 350 =============
PE 351
257ac0 352 Of course the Web is more than just markup. You need static assets: CSS, JS,
SP 353 and images. Let's point our web app at a directory from which Pyramid will
354 serve some static assets. First let's make another call to the
715ec5 355 :term:`configurator` in ``app.py``:
47eaa1 356
ae9014 357 .. literalinclude:: quick_tour/static_assets/app.py
715ec5 358     :language: python
257ac0 359     :linenos:
SP 360     :lines: 6-8
361     :lineno-start: 6
362     :emphasize-lines: 2
47eaa1 363
PE 364 This tells our WSGI application to map requests under
257ac0 365 http://localhost:6543/static/ to files and directories inside a ``static``
SP 366 directory alongside our Python module.
47eaa1 367
1273d0 368 Next make a directory named ``static``, and place ``app.css`` inside:
47eaa1 369
ae9014 370 .. literalinclude:: quick_tour/static_assets/static/app.css
d559af 371     :language: css
47eaa1 372
257ac0 373 All we need to do now is point to it in the ``<head>`` of our Jinja2 template,
SP 374 ``hello_world.jinja2``:
47eaa1 375
715ec5 376 .. literalinclude:: quick_tour/static_assets/hello_world_static.jinja2
257ac0 377     :language: jinja
SP 378     :linenos:
379     :lines: 4-6
380     :lineno-start: 4
381     :emphasize-lines: 2
47eaa1 382
257ac0 383 This link presumes that our CSS is at a URL starting with ``/static/``. What if
SP 384 the site is later moved under ``/somesite/static/``? Or perhaps a web developer
385 changes the arrangement on disk? Pyramid provides a helper to allow flexibility
386 on URL generation:
d559af 387
715ec5 388 .. literalinclude:: quick_tour/static_assets/hello_world.jinja2
257ac0 389     :language: jinja
SP 390     :linenos:
391     :lines: 4-6
392     :lineno-start: 4
393     :emphasize-lines: 2
d559af 394
715ec5 395 By using ``request.static_url`` to generate the full URL to the static assets,
SP 396 you ensure that you stay in sync with the configuration and gain refactoring
397 flexibility later.
47eaa1 398
2033ee 399 .. seealso:: See also:
b731b5 400     :ref:`Quick Tutorial Static Assets <qtut_static_assets>`,
257ac0 401     :doc:`../narr/assets`, :ref:`preventing_http_caching`, and
SP 402     :ref:`influencing_http_caching`.
403
5b47ba 404
47eaa1 405 Returning JSON
PE 406 ==============
407
257ac0 408 Modern web apps are more than rendered HTML. Dynamic pages now use JavaScript
SP 409 to update the UI in the browser by requesting server data as JSON. Pyramid
410 supports this with a JSON renderer:
47eaa1 411
ae9014 412 .. literalinclude:: quick_tour/json/views.py
da42d5 413     :language: python
257ac0 414     :linenos:
SP 415     :lines: 9-
416     :lineno-start: 9
47eaa1 417
257ac0 418 This wires up a view that returns some data through the JSON :term:`renderer`,
SP 419 which calls Python's JSON support to serialize the data into JSON, and sets the
420 appropriate HTTP headers.
421
422 We also need to add a route to ``app.py`` so that our app will know how to
423 respond to a request for ``hello.json``.
424
425 .. literalinclude:: quick_tour/json/app.py
da42d5 426     :language: python
257ac0 427     :linenos:
SP 428     :lines: 6-8
429     :lineno-start: 6
430     :emphasize-lines: 2
5b47ba 431
2033ee 432 .. seealso:: See also:
257ac0 433     :ref:`Quick Tutorial JSON <qtut_json>`, :ref:`views_which_use_a_renderer`,
SP 434     :ref:`json_renderer`, and :ref:`adding_and_overriding_renderers`.
435
47eaa1 436
1273d0 437 View classes
47eaa1 438 ============
PE 439
257ac0 440 So far our views have been simple, free-standing functions. Many times your
SP 441 views are related. They may have different ways to look at or work on the same
442 data, or they may be a REST API that handles multiple operations. Grouping
443 these together as a :ref:`view class <class_as_view>` makes sense and achieves
444 the following goals.
47eaa1 445
65d171 446 - Group views
47eaa1 447
65d171 448 - Centralize some repetitive defaults
47eaa1 449
65d171 450 - Share some state and helpers
47eaa1 451
257ac0 452 The following shows a "Hello World" example with three operations: view a form,
SP 453 save a change, or press the delete button in our ``views.py``:
47eaa1 454
ae9014 455 .. literalinclude:: quick_tour/view_classes/views.py
da42d5 456     :language: python
257ac0 457     :linenos:
SP 458     :lines: 7-
459     :lineno-start: 7
47eaa1 460
257ac0 461 As you can see, the three views are logically grouped together. Specifically:
47eaa1 462
257ac0 463 - The first view is returned when you go to ``/howdy/amy``. This URL is mapped
SP 464   to the ``hello`` route that we centrally set using the optional
65d171 465   ``@view_defaults``.
47eaa1 466
65d171 467 - The second view is returned when the form data contains a field with
257ac0 468   ``form.edit``, such as clicking on ``<input type="submit" name="form.edit"
SP 469   value="Save">``. This rule is specified in the ``@view_config`` for that
470   view.
d559af 471
257ac0 472 - The third view is returned when clicking on a button such as ``<input
SP 473   type="submit" name="form.delete" value="Delete">``.
d559af 474
257ac0 475 Only one route is needed, stated in one place atop the view class. Also, the
SP 476 assignment of ``name`` is done in the ``__init__`` function. Our templates can
477 then use ``{{ view.name }}``.
5b47ba 478
257ac0 479 Pyramid view classes, combined with built-in and custom predicates, have much
SP 480 more to offer:
b731b5 481
PE 482 - All the same view configuration parameters as function views
483
257ac0 484 - One route leading to multiple views, based on information in the request or
SP 485   data such as ``request_param``, ``request_method``, ``accept``, ``header``,
486   ``xhr``, ``containment``, and ``custom_predicates``
b731b5 487
2033ee 488 .. seealso:: See also:
257ac0 489     :ref:`Quick Tutorial View Classes <qtut_view_classes>`, :ref:`Quick
SP 490     Tutorial More View Classes <qtut_more_view_classes>`, and
491     :ref:`class_as_view`.
492
47eaa1 493
a0ebd7 494 Quick project startup with cookiecutters
SP 495 ========================================
47eaa1 496
5cf8c3 497 So far we have done all of our *Quick Tour* as a single Python file. No Python
SP 498 packages, no structure. Most Pyramid projects, though, aren't developed this
499 way.
47eaa1 500
2cd1ea 501 To ease the process of getting started, the Pylons Project provides :term:`cookiecutter`\ s that generate sample Pyramid projects from project templates. These cookiecutters will install Pyramid and its dependencies as well.
a0ebd7 502
SP 503 First you'll need to install cookiecutter.
47eaa1 504
PE 505 .. code-block:: bash
506
a0ebd7 507     $ $VENV/bin/pip install cookiecutter
47eaa1 508
2cd1ea 509 Let's use the cookiecutter ``pyramid-cookiecutter-starter`` to create a starter Pyramid project in the current directory, entering values at the prompts as shown below for the following command.
47eaa1 510
PE 511 .. code-block:: bash
512
1aa283 513     $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch
47eaa1 514
a0ebd7 515 If prompted for the first item, accept the default ``yes`` by hitting return.
SP 516
2cd381 517 .. code-block:: text
SP 518
519     You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.
520     Is it okay to delete and re-clone it? [yes]: yes
521     project_name [Pyramid Scaffold]: hello_world
6ff6fa 522     repo_name [hello_world]: hello_world
2cd381 523     Select template_language:
SP 524     1 - jinja2
525     2 - chameleon
6204d8 526     3 - mako
SP 527     Choose from 1, 2, 3 [1]: 1
a0ebd7 528
b488f7 529 We then run through the following commands.
47eaa1 530
PE 531 .. code-block:: bash
532
a0ebd7 533     # Change directory into your newly created project.
2cd1ea 534     $ cd hello_world
a0ebd7 535     # Create a new virtual environment...
SP 536     $ python3 -m venv env
537     # ...where we upgrade packaging tools...
538     $ env/bin/pip install --upgrade pip setuptools
539     # ...and into which we install our project and its testing requirements.
540     $ env/bin/pip install -e ".[testing]"
2cd1ea 541     # Reset our environment variable for a new virtual environment.
b488f7 542     $ export VENV=~/hello_world/env
47eaa1 543
5cf8c3 544 We are moving in the direction of a full-featured Pyramid project, with a
SP 545 proper setup for Python standards (packaging) and Pyramid configuration. This
546 includes a new way of running your application:
47eaa1 547
PE 548 .. code-block:: bash
549
ebbe68 550     $ $VENV/bin/pserve development.ini
47eaa1 551
PE 552 Let's look at ``pserve`` and configuration in more depth.
5b47ba 553
2033ee 554 .. seealso:: See also:
49cd00 555     :ref:`Quick Tutorial Cookiecutters <qtut_cookiecutters>`,
b731b5 556     :ref:`project_narr`, and
d5b5d0 557     :doc:`../narr/cookiecutters`
47eaa1 558
1273d0 559 Application running with ``pserve``
47eaa1 560 ===================================
PE 561
2cd1ea 562 Prior to the cookiecutter, our project mixed a number of operational details into our
5cf8c3 563 code. Why should my main code care which HTTP server I want and what port
SP 564 number to run on?
d4bd29 565
5cf8c3 566 ``pserve`` is Pyramid's application runner, separating operational details from
SP 567 your code. When you install Pyramid, a small command program called ``pserve``
568 is written to your ``bin`` directory. This program is an executable Python
569 module. It's very small, getting most of its brains via import.
47eaa1 570
5cf8c3 571 You can run ``pserve`` with ``--help`` to see some of its options. Doing so
SP 572 reveals that you can ask ``pserve`` to watch your development files and reload
573 the server when they change:
47eaa1 574
PE 575 .. code-block:: bash
576
ebbe68 577     $ $VENV/bin/pserve development.ini --reload
47eaa1 578
5cf8c3 579 The ``pserve`` command has a number of other options and operations. Most of
SP 580 the work, though, comes from your project's wiring, as expressed in the
581 configuration file you supply to ``pserve``. Let's take a look at this
582 configuration file.
49d634 583
2033ee 584 .. seealso:: See also:
b731b5 585     :ref:`what_is_this_pserve_thing`
47eaa1 586
1273d0 587 Configuration with ``.ini`` files
47eaa1 588 =================================
PE 589
5cf8c3 590 Earlier in *Quick Tour* we first met Pyramid's configuration system. At that
SP 591 point we did all configuration in Python code. For example, the port number
2cd1ea 592 chosen for our HTTP server was right there in Python code. Our cookiecutter has
5cf8c3 593 moved this decision and more into the ``development.ini`` file:
d4bd29 594
ae9014 595 .. literalinclude:: quick_tour/package/development.ini
d4bd29 596     :language: ini
47eaa1 597
5cf8c3 598 Let's take a quick high-level look. First the ``.ini`` file is divided into
SP 599 sections:
47eaa1 600
5cf8c3 601 - ``[app:main]`` configures our WSGI app
47eaa1 602
PE 603 - ``[server:main]`` holds our WSGI server settings
604
605 - Various sections afterwards configure our Python logging system
606
d4bd29 607 We have a few decisions made for us in this configuration:
47eaa1 608
1273d0 609 #. *WSGI app:* What package has our WSGI application in it?
5cf8c3 610    ``use = egg:hello_world`` in the app section tells the configuration what
SP 611    application to load.
47eaa1 612
1273d0 613 #. *Easier development by automatic template reloading:* In development mode,
SP 614    you shouldn't have to restart the server when editing a Jinja2 template.
5cf8c3 615    ``pyramid.reload_templates = true`` sets this policy, which might be
SP 616    different in production.
47eaa1 617
785776 618 #. *Choice of web server:* ``use = egg:waitress#main`` tells ``pserve`` to
SP 619    use the ``waitress`` server.
620
6d120e 621 #. *Interfaces:* ``listen = localhost:6543`` tells ``waitress`` to listen on all interfaces on port 6543 for both IPv4 and IPv6.
785776 622
d5b5d0 623 Additionally the ``development.ini`` generated by this cookiecutter wired up
5cf8c3 624 Python's standard logging. We'll now see in the console, for example, a log on
SP 625 every request that comes in, as well as traceback information.
47eaa1 626
2033ee 627 .. seealso:: See also:
b731b5 628     :ref:`Quick Tutorial Application Configuration <qtut_ini>`,
PE 629     :ref:`environment_chapter` and
630     :doc:`../narr/paste`
49d634 631
5b47ba 632
1273d0 633 Easier development with ``debugtoolbar``
47eaa1 634 ========================================
PE 635
58febc 636 As we introduce the basics, we also want to show how to be productive in
5cf8c3 637 development and debugging. For example, we just discussed template reloading
SP 638 and earlier we showed ``--reload`` for application reloading.
47eaa1 639
5cf8c3 640 ``pyramid_debugtoolbar`` is a popular Pyramid add-on which makes several tools
SP 641 available in your browser. Adding it to your project illustrates several points
642 about configuration.
47eaa1 643
af1e32 644 The cookiecutter ``pyramid-cookiecutter-starter`` already configured our package to include the
5cf8c3 645 add-on ``pyramid_debugtoolbar`` in its ``setup.py``:
47eaa1 646
ae9014 647 .. literalinclude:: quick_tour/package/setup.py
5cf8c3 648     :language: python
af1e32 649     :lineno-match:
65a6d3 650     :lines: 11-17
SP 651     :emphasize-lines: 5
47eaa1 652
5cf8c3 653 It was installed when you previously ran:
47eaa1 654
PE 655 .. code-block:: bash
656
af1e32 657     $ $VENV/bin/pip install -e ".[testing]"
47eaa1 658
5cf8c3 659 The ``pyramid_debugtoolbar`` package is a Pyramid add-on, which means we need
65a6d3 660 to include its configuration into our web application. The cookiecutter already took care of this for us in its ``development.ini`` using the ``pyramid.includes`` facility:
47eaa1 661
ae9014 662 .. literalinclude:: quick_tour/package/development.ini
d4bd29 663     :language: ini
af1e32 664     :lineno-match:
SP 665     :lines: 14-15
47eaa1 666
5cf8c3 667 You'll now see a Pyramid logo on the right side of your browser window, which
SP 668 when clicked opens a new window that provides introspective access to debugging
669 information. Even better, if your web application generates an error, you will
670 see a nice traceback on the screen. When you want to disable this toolbar,
671 there's no need to change code: you can remove it from ``pyramid.includes`` in
672 the relevant ``.ini`` configuration file.
5b47ba 673
2033ee 674 .. seealso:: See also:
5cf8c3 675     :ref:`Quick Tutorial pyramid_debugtoolbar <qtut_debugtoolbar>` and
b731b5 676     :ref:`pyramid_debugtoolbar <toolbar:overview>`
47eaa1 677
ebbe68 678 Unit tests and ``py.test``
SP 679 ==========================
47eaa1 680
5cf8c3 681 Yikes! We got this far and we haven't yet discussed tests. This is particularly
SP 682 egregious, as Pyramid has had a deep commitment to full test coverage since
683 before its release.
47eaa1 684
948344 685 Our ``pyramid-cookiecutter-starter`` cookiecutter generated a ``tests.py`` module with
SP 686 one unit test and one functional test in it. It also configured ``setup.py`` with test requirements:
371d11 687 ``py.test`` as the test runner, ``WebTest`` for running view tests, and the
65a6d3 688 ``pytest-cov`` tool which yells at us for code that isn't tested:
47eaa1 689
948344 690 .. literalinclude:: quick_tour/package/setup.py
SP 691     :language: python
692     :lineno-match:
65a6d3 693     :lines: 19-23
47eaa1 694
948344 695 .. literalinclude:: quick_tour/package/setup.py
SP 696     :language: python
697     :lineno-match:
65a6d3 698     :lines: 43-45
47eaa1 699
948344 700 We already installed the test requirements when we ran the command ``$VENV/bin/pip install -e ".[testing]"``. We can now run all our tests:
47eaa1 701
PE 702 .. code-block:: bash
703
683d75 704     $ $VENV/bin/py.test --cov --cov-report=term-missing
47eaa1 705
ebbe68 706 This yields the following output.
47eaa1 707
ebbe68 708 .. code-block:: text
SP 709
710     =========================== test session starts ===========================
948344 711     platform darwin -- Python 3.6.0, pytest-3.0.5, py-1.4.32, pluggy-0.4.0
SP 712     rootdir: /Users/stevepiercy/hello_world, inifile: pytest.ini
713     plugins: cov-2.4.0
714     collected 2 items
ebbe68 715
948344 716     hello_world/tests.py ..
SP 717
c8a5e0 718     ------------- coverage: platform darwin, python 3.6.0-final-0 -------------
948344 719     Name                                      Stmts   Miss  Cover   Missing
SP 720     -----------------------------------------------------------------------
721     hello_world/__init__.py                       8      0   100%
722     hello_world/views.py                          3      0   100%
723     -----------------------------------------------------------------------
724     TOTAL                                        11      0   100%
ebbe68 725
SP 726
948344 727     ========================= 2 passed in 1.37 seconds =========================
SP 728
729 Our tests passed, and its coverage is complete. What did our test look like?
47eaa1 730
ae9014 731 .. literalinclude:: quick_tour/package/hello_world/tests.py
da42d5 732     :language: python
5cf8c3 733     :linenos:
47eaa1 734
5cf8c3 735 Pyramid supplies helpers for test writing, which we use in the test setup and
948344 736 teardown. Our first test imports the view, makes a dummy request, and sees if the
SP 737 view returns what we expected. Our second test verifies that the response body from a request to the web root contains what we expected.
47eaa1 738
2033ee 739 .. seealso:: See also:
5cf8c3 740     :ref:`Quick Tutorial Unit Testing <qtut_unit_testing>`, :ref:`Quick
SP 741     Tutorial Functional Testing <qtut_functional_testing>`, and
b731b5 742     :ref:`testing_chapter`
5b47ba 743
83fefb 744 Logging
PE 745 =======
746
5cf8c3 747 It's important to know what is going on inside our web application. In
SP 748 development we might need to collect some output. In production we might need
749 to detect situations when other people use the site. We need *logging*.
83fefb 750
c87565 751 Fortunately Pyramid uses the normal Python approach to logging. The ``development.ini`` file for your project has a number of lines that configure the
5cf8c3 752 logging for you to some reasonable defaults. You then see messages sent by
SP 753 Pyramid (for example, when a new request comes in).
83fefb 754
5cf8c3 755 Maybe you would like to log messages in your code? In your Python module,
c87565 756 import and set up the logging in your ``views.py``:
83fefb 757
c87565 758 .. literalinclude:: quick_tour/logging/hello_world/views.py
5cf8c3 759     :language: python
c87565 760     :lineno-match:
5cf8c3 761     :lines: 3-4
83fefb 762
PE 763 You can now, in your code, log messages:
764
c87565 765 .. literalinclude:: quick_tour/logging/hello_world/views.py
5cf8c3 766     :language: python
c87565 767     :lineno-match:
SP 768     :lines: 7-8
5cf8c3 769     :emphasize-lines: 2
83fefb 770
c87565 771 This will log ``Some Message`` at a ``DEBUG`` log level to the
5cf8c3 772 application-configured logger in your ``development.ini``. What controls that?
SP 773 These emphasized sections in the configuration file:
83fefb 774
c87565 775 .. literalinclude:: quick_tour/logging/development.ini
d4bd29 776     :language: ini
c87565 777     :lineno-match:
SP 778     :lines: 34-50
5cf8c3 779     :emphasize-lines: 1-2,14-17
83fefb 780
5cf8c3 781 Our application, a package named ``hello_world``, is set up as a logger and
SP 782 configured to log messages at a ``DEBUG`` or higher level. When you visit
556258 783 http://localhost:6543, your console will now show:
SP 784
785 .. code-block:: text
d4bd29 786
c87565 787     2016-12-25 03:03:57,059 DEBUG [hello_world.views:8][waitress] Some Message
5b47ba 788
2033ee 789 .. seealso:: See also:
5cf8c3 790     :ref:`Quick Tutorial Logging <qtut_logging>` and :ref:`logging_chapter`.
83fefb 791
PE 792 Sessions
793 ========
794
5cf8c3 795 When people use your web application, they frequently perform a task that
SP 796 requires semi-permanent data to be saved. For example, a shopping cart. This is
797 called a :term:`session`.
83fefb 798
5cf8c3 799 Pyramid has basic built-in support for sessions. Third party packages such as
SP 800 ``pyramid_redis_sessions`` provide richer session support. Or you can create
801 your own custom sessioning engine. Let's take a look at the :doc:`built-in
802 sessioning support <../narr/sessions>`. In our ``__init__.py`` we first import
803 the kind of sessioning we want:
83fefb 804
64009a 805 .. literalinclude:: quick_tour/sessions/hello_world/__init__.py
5cf8c3 806     :language: python
64009a 807     :lineno-match:
SP 808     :lines: 1-2
5cf8c3 809     :emphasize-lines: 2
83fefb 810
d4bd29 811 .. warning::
83fefb 812
5cf8c3 813     As noted in the session docs, this example implementation is not intended
SP 814     for use in settings with security implications.
83fefb 815
d4bd29 816 Now make a "factory" and pass it to the :term:`configurator`'s
PE 817 ``session_factory`` argument:
83fefb 818
64009a 819 .. literalinclude:: quick_tour/sessions/hello_world/__init__.py
5cf8c3 820     :language: python
64009a 821     :lineno-match:
SP 822     :lines: 10-13
823     :emphasize-lines: 2-3
83fefb 824
5cf8c3 825 Pyramid's :term:`request` object now has a ``session`` attribute that we can
SP 826 use in our view code in ``views.py``:
83fefb 827
64009a 828 .. literalinclude:: quick_tour/sessions/hello_world/views.py
5cf8c3 829     :language: python
64009a 830     :lineno-match:
SP 831     :lines: 7-
5cf8c3 832     :emphasize-lines: 3-7
83fefb 833
64009a 834 We need to update our Jinja2 template ``templates/mytemplate.jinja2`` to show counter increment in the session:
d4bd29 835
64009a 836 .. literalinclude:: quick_tour/sessions/hello_world/templates/mytemplate.jinja2
d4bd29 837     :language: jinja
64009a 838     :lineno-match:
SP 839     :lines: 4-8
840     :emphasize-lines: 4
d4bd29 841
2033ee 842 .. seealso:: See also:
5cf8c3 843     :ref:`Quick Tutorial Sessions <qtut_sessions>`, :ref:`sessions_chapter`,
SP 844     :ref:`flash_messages`, :ref:`session_module`, and
845     :term:`pyramid_redis_sessions`.
83fefb 846
PE 847
848 Databases
849 =========
850
6a9366 851 Web applications mean data. Data means databases. Frequently SQL databases. SQL
SP 852 databases frequently mean an "ORM" (object-relational mapper.) In Python, ORM
853 usually leads to the mega-quality *SQLAlchemy*, a Python package that greatly
854 eases working with databases.
83fefb 855
b488f7 856 Pyramid and SQLAlchemy are great friends. That friendship includes a cookiecutter!
83fefb 857
PE 858 .. code-block:: bash
859
b488f7 860     $ cd ~
1aa283 861     $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch
b488f7 862
SP 863 If prompted for the first item, accept the default ``yes`` by hitting return.
864
2cd381 865 .. code-block:: text
SP 866
867     You've cloned ~/.cookiecutters/pyramid-cookiecutter-alchemy before.
868     Is it okay to delete and re-clone it? [yes]: yes
869     project_name [Pyramid Scaffold]: sqla_demo
6ff6fa 870     repo_name [sqla_demo]: sqla_demo
b488f7 871
SP 872 We then run through the following commands as before.
873
874 .. code-block:: bash
875
876     # Change directory into your newly created project.
877     $ cd sqla_demo
878     # Create a new virtual environment...
879     $ python3 -m venv env
880     # ...where we upgrade packaging tools...
881     $ env/bin/pip install --upgrade pip setuptools
882     # ...and into which we install our project and its testing requirements.
883     $ env/bin/pip install -e ".[testing]"
884     # Reset our environment variable for a new virtual environment.
885     $ export VENV=~/sqla_demo/env
83fefb 886
6a9366 887 We now have a working sample SQLAlchemy application with all dependencies
SP 888 installed. The sample project provides a console script to initialize a SQLite
889 database with tables. Let's run it, then start the application:
83fefb 890
PE 891 .. code-block:: bash
892
ebbe68 893   $ $VENV/bin/initialize_sqla_demo_db development.ini
SP 894   $ $VENV/bin/pserve development.ini
83fefb 895
6a9366 896 The ORM eases the mapping of database structures into a programming language.
d5b5d0 897 SQLAlchemy uses "models" for this mapping. The cookiecutter generated a sample
6a9366 898 model:
83fefb 899
414b67 900 .. literalinclude:: quick_tour/sqla_demo/sqla_demo/models/mymodel.py
da42d5 901     :language: python
b488f7 902     :lineno-match:
SP 903     :pyobject: MyModel
83fefb 904
6a9366 905 View code, which mediates the logic between web requests and the rest of the
SP 906 system, can then easily get at the data thanks to SQLAlchemy:
83fefb 907
3eb1c3 908 .. literalinclude:: quick_tour/sqla_demo/sqla_demo/views/default.py
da42d5 909     :language: python
b488f7 910     :lineno-match:
SP 911     :lines: 13
5b47ba 912
2033ee 913 .. seealso:: See also:
6a9366 914     :ref:`Quick Tutorial Databases <qtut_databases>`, `SQLAlchemy
SP 915     <http://www.sqlalchemy.org/>`_, :ref:`making_a_console_script`,
916     :ref:`bfg_sql_wiki_tutorial`, and :ref:`Application Transactions with
917     pyramid_tm <tm:overview>`.
918
47eaa1 919
83fefb 920 Forms
PE 921 =====
47eaa1 922
6a9366 923 Developers have lots of opinions about web forms, thus there are many form
SP 924 libraries for Python. Pyramid doesn't directly bundle a form library, but
925 *Deform* is a popular choice for forms, along with its related *Colander*
926 schema system.
47eaa1 927
6a9366 928 As an example, imagine we want a form that edits a wiki page. The form should
SP 929 have two fields on it, one of them a required title and the other a rich text
930 editor for the body. With Deform we can express this as a Colander schema:
83fefb 931
d4bd29 932 .. code-block:: python
PE 933
934     class WikiPage(colander.MappingSchema):
935         title = colander.SchemaNode(colander.String())
936         body = colander.SchemaNode(
937             colander.String(),
938             widget=deform.widget.RichTextWidget()
939         )
940
6a9366 941 With this in place, we can render the HTML for a form, perhaps with form data
SP 942 from an existing page:
d4bd29 943
PE 944 .. code-block:: python
945
946     form = self.wiki_form.render()
947
948 We'd like to handle form submission, validation, and saving:
949
950 .. code-block:: python
951
952     # Get the form data that was posted
953     controls = self.request.POST.items()
954     try:
955         # Validate and either raise a validation error
956         # or return deserialized data from widgets
957         appstruct = wiki_form.validate(controls)
958     except deform.ValidationFailure as e:
959         # Bail out and render form with errors
960         return dict(title=title, page=page, form=e.render())
961
962     # Change the content and redirect to the view
963     page['title'] = appstruct['title']
964     page['body'] = appstruct['body']
965
6a9366 966 Deform and Colander provide a very flexible combination for forms, widgets,
SP 967 schemas, and validation. Recent versions of Deform also include a :ref:`retail
968 mode <deform:retail>` for gaining Deform features on custom forms.
d4bd29 969
a0ad6f 970 Deform uses attractive CSS from Twitter Bootstrap and more powerful select, checkbox, and date and time widgets.
d4bd29 971
2033ee 972 .. seealso:: See also:
a0ad6f 973     :ref:`Quick Tutorial Forms <qtut_forms>`, :ref:`Deform <deform:overview>`, and :ref:`Colander <colander:overview>`.
83fefb 974
d4bd29 975 Conclusion
PE 976 ==========
83fefb 977
ae9014 978 This *Quick Tour* covered a little about a lot. We introduced a long list
PE 979 of concepts in Pyramid, many of which are expanded on more fully in the
540fcd 980 Pyramid developer docs.