commit | author | age
|
e0887e
|
1 |
.. index:: |
CM |
2 |
single: Agendaless Consulting |
|
3 |
single: Pylons |
|
4 |
single: Django |
|
5 |
single: Zope |
9ec2d6
|
6 |
single: frameworks vs. libraries |
CM |
7 |
single: framework |
e0887e
|
8 |
|
fd5ae9
|
9 |
:app:`Pyramid` Introduction |
ca00fb
|
10 |
=========================== |
9e3bdb
|
11 |
|
b0d207
|
12 |
:app:`Pyramid` is a general, open source, Python web application development |
7a505d
|
13 |
*framework*. Its primary goal is to make it easier for a Python developer to |
CM |
14 |
create web applications. |
9e3bdb
|
15 |
|
9ec2d6
|
16 |
.. sidebar:: Frameworks vs. Libraries |
CM |
17 |
|
ca00fb
|
18 |
A *framework* differs from a *library* in one very important way: library |
SP |
19 |
code is always *called* by code that you write, while a framework always |
|
20 |
*calls* code that you write. Using a set of libraries to create an |
|
21 |
application is usually easier than using a framework initially, because you |
|
22 |
can choose to cede control to library code you have not authored very |
|
23 |
selectively. But when you use a framework, you are required to cede a |
|
24 |
greater portion of control to code you have not authored: code that resides |
|
25 |
in the framework itself. You needn't use a framework at all to create a web |
|
26 |
application using Python. A rich set of libraries already exists for the |
|
27 |
platform. In practice, however, using a framework to create an application |
|
28 |
is often more practical than rolling your own via a set of libraries if the |
|
29 |
framework provides a set of facilities that fits your application |
|
30 |
requirements. |
0bc787
|
31 |
|
b20299
|
32 |
Pyramid attempts to follow these design and engineering principles: |
9e3bdb
|
33 |
|
878328
|
34 |
Simplicity |
7a505d
|
35 |
:app:`Pyramid` takes a *"pay only for what you eat"* approach. You can get |
ca00fb
|
36 |
results even if you have only a partial understanding of :app:`Pyramid`. It |
SP |
37 |
doesn't force you to use any particular technology to produce an application, |
|
38 |
and we try to keep the core set of concepts that you need to understand to a |
|
39 |
minimum. |
9e3bdb
|
40 |
|
878328
|
41 |
Minimalism |
ca00fb
|
42 |
:app:`Pyramid` tries to solve only the fundamental problems of creating a web |
SP |
43 |
application: the mapping of URLs to code, templating, security, and serving |
|
44 |
static assets. We consider these to be the core activities that are common to |
|
45 |
nearly all web applications. |
9e3bdb
|
46 |
|
878328
|
47 |
Documentation |
ca00fb
|
48 |
Pyramid's minimalism means that it is easier for us to maintain complete and |
SP |
49 |
up-to-date documentation. It is our goal that no aspect of Pyramid is |
|
50 |
undocumented. |
9e3bdb
|
51 |
|
878328
|
52 |
Speed |
b0d207
|
53 |
:app:`Pyramid` is designed to provide noticeably fast execution for common |
01c184
|
54 |
tasks such as templating and simple response generation. |
9e3bdb
|
55 |
|
b0d207
|
56 |
Reliability |
CM |
57 |
:app:`Pyramid` is developed conservatively and tested exhaustively. Where |
ca00fb
|
58 |
Pyramid source code is concerned, our motto is: "If it ain't tested, it's |
bb93cb
|
59 |
broke". |
878328
|
60 |
|
9ec2d6
|
61 |
Openness |
ca00fb
|
62 |
As with Python, the Pyramid software is distributed under a `permissive open |
SP |
63 |
source license <http://repoze.org/license.html>`_. |
3ea7c7
|
64 |
|
d8fc16
|
65 |
.. _what_makes_pyramid_unique: |
CM |
66 |
|
d59239
|
67 |
What makes Pyramid unique |
bb93cb
|
68 |
------------------------- |
CM |
69 |
|
|
70 |
Understandably, people don't usually want to hear about squishy engineering |
ca00fb
|
71 |
principles; they want to hear about concrete stuff that solves their problems. |
SP |
72 |
With that in mind, what would make someone want to use Pyramid instead of one |
|
73 |
of the many other web frameworks available today? What makes Pyramid unique? |
bb93cb
|
74 |
|
ca00fb
|
75 |
This is a hard question to answer because there are lots of excellent choices, |
SP |
76 |
and it's actually quite hard to make a wrong choice, particularly in the Python |
|
77 |
web framework market. But one reasonable answer is this: you can write very |
|
78 |
small applications in Pyramid without needing to know a lot. "What?" you say. |
|
79 |
"That can't possibly be a unique feature. Lots of other web frameworks let you |
|
80 |
do that!" Well, you're right. But unlike many other systems, you can also |
|
81 |
write very large applications in Pyramid if you learn a little more about it. |
|
82 |
Pyramid will allow you to become productive quickly, and will grow with you. It |
|
83 |
won't hold you back when your application is small, and it won't get in your |
|
84 |
way when your application becomes large. "Well that's fine," you say. "Lots of |
|
85 |
other frameworks let me write large apps, too." Absolutely. But other Python |
|
86 |
web frameworks don't seamlessly let you do both. They seem to fall into two |
|
87 |
non-overlapping categories: frameworks for "small apps" and frameworks for "big |
|
88 |
apps". The "small app" frameworks typically sacrifice "big app" features, and |
|
89 |
vice versa. |
bb93cb
|
90 |
|
CM |
91 |
We don't think it's a universally reasonable suggestion to write "small apps" |
|
92 |
in a "small framework" and "big apps" in a "big framework". You can't really |
ca00fb
|
93 |
know to what size every application will eventually grow. We don't really want |
SP |
94 |
to have to rewrite a previously small application in another framework when it |
|
95 |
gets "too big". We believe the current binary distinction between frameworks |
|
96 |
for small and large applications is just false. A well-designed framework |
|
97 |
should be able to be good at both. Pyramid strives to be that kind of |
|
98 |
framework. |
bb93cb
|
99 |
|
ca00fb
|
100 |
To this end, Pyramid provides a set of features that combined are unique |
bb93cb
|
101 |
amongst Python web frameworks. Lots of other frameworks contain some |
d59239
|
102 |
combination of these features. Pyramid of course actually stole many of them |
ca00fb
|
103 |
from those other frameworks. But Pyramid is the only one that has all of them |
SP |
104 |
in one place, documented appropriately, and useful *à la carte* without |
bb93cb
|
105 |
necessarily paying for the entire banquet. These are detailed below. |
CM |
106 |
|
d3aae8
|
107 |
Single-file applications |
bb93cb
|
108 |
~~~~~~~~~~~~~~~~~~~~~~~~ |
CM |
109 |
|
ca00fb
|
110 |
You can write a Pyramid application that lives entirely in one Python file, not |
SP |
111 |
unlike existing Python microframeworks. This is beneficial for one-off |
|
112 |
prototyping, bug reproduction, and very small applications. These applications |
|
113 |
are easy to understand because all the information about the application lives |
|
114 |
in a single place, and you can deploy them without needing to understand much |
|
115 |
about Python distributions and packaging. Pyramid isn't really marketed as a |
|
116 |
microframework, but it allows you to do almost everything that frameworks that |
|
117 |
are marketed as "micro" offer in very similar ways. |
bb93cb
|
118 |
|
d3aae8
|
119 |
.. literalinclude:: helloworld.py |
bb93cb
|
120 |
|
2033ee
|
121 |
.. seealso:: |
SP |
122 |
|
|
123 |
See also :ref:`firstapp_chapter`. |
d3aae8
|
124 |
|
CM |
125 |
Decorator-based configuration |
bb93cb
|
126 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
CM |
127 |
|
|
128 |
If you like the idea of framework configuration statements living next to the |
|
129 |
code it configures, so you don't have to constantly switch between files to |
|
130 |
refer to framework configuration when adding new code, you can use Pyramid |
bdebfb
|
131 |
decorators to localize the configuration. For example: |
CM |
132 |
|
|
133 |
.. code-block:: python |
|
134 |
|
|
135 |
from pyramid.view import view_config |
|
136 |
from pyramid.response import Response |
bb93cb
|
137 |
|
CM |
138 |
@view_config(route_name='fred') |
|
139 |
def fred_view(request): |
|
140 |
return Response('fred') |
|
141 |
|
ca00fb
|
142 |
However, unlike some other systems, using decorators for Pyramid configuration |
SP |
143 |
does not make your application difficult to extend, test, or reuse. The |
|
144 |
:class:`~pyramid.view.view_config` decorator, for example, does not actually |
|
145 |
*change* the input or output of the function it decorates, so testing it is a |
|
146 |
"WYSIWYG" operation. You don't need to understand the framework to test your |
|
147 |
own code. You just behave as if the decorator is not there. You can also |
|
148 |
instruct Pyramid to ignore some decorators, or use completely imperative |
|
149 |
configuration instead of decorators to add views. Pyramid decorators are inert |
|
150 |
instead of eager. You detect and activate them with a :term:`scan`. |
bb93cb
|
151 |
|
CM |
152 |
Example: :ref:`mapping_views_using_a_decorator_section`. |
|
153 |
|
d3aae8
|
154 |
URL generation |
bb93cb
|
155 |
~~~~~~~~~~~~~~ |
CM |
156 |
|
ca00fb
|
157 |
Pyramid is capable of generating URLs for resources, routes, and static assets. |
SP |
158 |
Its URL generation APIs are easy to use and flexible. If you use Pyramid's |
|
159 |
various APIs for generating URLs, you can change your configuration around |
|
160 |
arbitrarily without fear of breaking a link on one of your web pages. |
bb93cb
|
161 |
|
CM |
162 |
Example: :ref:`generating_route_urls`. |
|
163 |
|
|
164 |
Static file serving |
|
165 |
~~~~~~~~~~~~~~~~~~~ |
|
166 |
|
|
167 |
Pyramid is perfectly willing to serve static files itself. It won't make you |
ca00fb
|
168 |
use some external web server to do that. You can even serve more than one set |
SP |
169 |
of static files in a single Pyramid web application (e.g., ``/static`` and |
|
170 |
``/static2``). You can optionally place your files on an external web server |
|
171 |
and ask Pyramid to help you generate URLs to those files. This let's you use |
|
172 |
Pyramid's internal file serving while doing development, and a faster static |
|
173 |
file server in production, without changing any code. |
bb93cb
|
174 |
|
CM |
175 |
Example: :ref:`static_assets_section`. |
|
176 |
|
d59239
|
177 |
Fully interactive development |
daefb5
|
178 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
KOP |
179 |
|
d84407
|
180 |
When developing a Pyramid application, several interactive features are |
4bc489
|
181 |
available. Pyramid can automatically utilize changed templates when rendering |
d59239
|
182 |
pages and automatically restart the application to incorporate changed Python |
4bc489
|
183 |
code. Plain old ``print()`` calls used for debugging can display to a console. |
bb93cb
|
184 |
|
CM |
185 |
Pyramid's debug toolbar comes activated when you use a Pyramid scaffold to |
|
186 |
render a project. This toolbar overlays your application in the browser, and |
d59239
|
187 |
allows you access to framework data, such as the routes configured, the last |
ca00fb
|
188 |
renderings performed, the current set of packages installed, SQLAlchemy queries |
SP |
189 |
run, logging data, and various other facts. When an exception occurs, you can |
|
190 |
use its interactive debugger to poke around right in your browser to try to |
|
191 |
determine the cause of the exception. It's handy. |
bb93cb
|
192 |
|
CM |
193 |
Example: :ref:`debug_toolbar`. |
|
194 |
|
|
195 |
Debugging settings |
|
196 |
~~~~~~~~~~~~~~~~~~ |
|
197 |
|
|
198 |
Pyramid has debugging settings that allow you to print Pyramid runtime |
ca00fb
|
199 |
information to the console when things aren't behaving as you're expecting. For |
SP |
200 |
example, you can turn on ``debug_notfound``, which prints an informative |
|
201 |
message to the console every time a URL does not match any view. You can turn |
|
202 |
on ``debug_authorization``, which lets you know why a view execution was |
bb93cb
|
203 |
allowed or denied by printing a message to the console. These features are |
CM |
204 |
useful for those WTF moments. |
|
205 |
|
cfb2b5
|
206 |
There are also a number of commands that you can invoke within a Pyramid |
d59239
|
207 |
environment that allow you to introspect the configuration of your system. |
ca00fb
|
208 |
``proutes`` shows all configured routes for an application in the order they'll |
SP |
209 |
be evaluated for matching. ``pviews`` shows all configured views for any given |
|
210 |
URL. These are also WTF-crushers in some circumstances. |
bb93cb
|
211 |
|
ab7b24
|
212 |
Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`. |
bb93cb
|
213 |
|
214125
|
214 |
Add-ons |
ca00fb
|
215 |
~~~~~~~ |
214125
|
216 |
|
CM |
217 |
Pyramid has an extensive set of add-ons held to the same quality standards as |
ca00fb
|
218 |
the Pyramid core itself. Add-ons are packages which provide functionality that |
SP |
219 |
the Pyramid core doesn't. Add-on packages already exist which let you easily |
|
220 |
send email, let you use the Jinja2 templating system, let you use XML-RPC or |
|
221 |
JSON-RPC, let you integrate with jQuery Mobile, etc. |
214125
|
222 |
|
d59239
|
223 |
Examples: |
c6729d
|
224 |
https://trypyramid.com/resources-extending-pyramid.html |
214125
|
225 |
|
d3aae8
|
226 |
Class-based and function-based views |
bb93cb
|
227 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
CM |
228 |
|
ca00fb
|
229 |
Pyramid has a structured, unified concept of a :term:`view callable`. View |
SP |
230 |
callables can be functions, methods of classes, or even instances. When you |
|
231 |
add a new view callable, you can choose to make it a function or a method of a |
|
232 |
class. In either case Pyramid treats it largely the same way. You can change |
|
233 |
your mind later and move code between methods of classes and functions. A |
|
234 |
collection of similar view callables can be attached to a single class as |
|
235 |
methods, if that floats your boat, and they can share initialization code as |
|
236 |
necessary. All kinds of views are easy to understand and use, and operate |
|
237 |
similarly. There is no phony distinction between them. They can be used for |
|
238 |
the same purposes. |
bb93cb
|
239 |
|
214125
|
240 |
Here's a view callable defined as a function: |
CM |
241 |
|
|
242 |
.. code-block:: python |
|
243 |
:linenos: |
|
244 |
|
|
245 |
from pyramid.response import Response |
|
246 |
from pyramid.view import view_config |
|
247 |
|
|
248 |
@view_config(route_name='aview') |
|
249 |
def aview(request): |
|
250 |
return Response('one') |
|
251 |
|
|
252 |
Here's a few views defined as methods of a class instead: |
|
253 |
|
|
254 |
.. code-block:: python |
|
255 |
:linenos: |
|
256 |
|
|
257 |
from pyramid.response import Response |
|
258 |
from pyramid.view import view_config |
|
259 |
|
|
260 |
class AView(object): |
|
261 |
def __init__(self, request): |
|
262 |
self.request = request |
|
263 |
|
|
264 |
@view_config(route_name='view_one') |
e73a54
|
265 |
def view_one(self): |
214125
|
266 |
return Response('one') |
CM |
267 |
|
|
268 |
@view_config(route_name='view_two') |
e73a54
|
269 |
def view_two(self): |
214125
|
270 |
return Response('two') |
CM |
271 |
|
2033ee
|
272 |
.. seealso:: |
SP |
273 |
|
|
274 |
See also :ref:`view_config_placement`. |
bb93cb
|
275 |
|
82dcba
|
276 |
.. _intro_asset_specs: |
CM |
277 |
|
|
278 |
Asset specifications |
|
279 |
~~~~~~~~~~~~~~~~~~~~ |
|
280 |
|
ca00fb
|
281 |
Asset specifications are strings that contain both a Python package name and a |
SP |
282 |
file or directory name, e.g., ``MyPackage:static/index.html``. Use of these |
|
283 |
specifications is omnipresent in Pyramid. An asset specification can refer to |
|
284 |
a template, a translation directory, or any other package-bound static |
d59239
|
285 |
resource. This makes a system built on Pyramid extensible because you don't |
82dcba
|
286 |
have to rely on globals ("*the* static directory") or lookup schemes ("*the* |
CM |
287 |
ordered set of template directories") to address your files. You can move |
|
288 |
files around as necessary, and include other packages that may not share your |
|
289 |
system's templates or static files without encountering conflicts. |
|
290 |
|
ca00fb
|
291 |
Because asset specifications are used heavily in Pyramid, we've also provided a |
SP |
292 |
way to allow users to override assets. Say you love a system that someone else |
|
293 |
has created with Pyramid but you just need to change "that one template" to |
|
294 |
make it all better. No need to fork the application. Just override the asset |
|
295 |
specification for that template with your own inside a wrapper, and you're good |
|
296 |
to go. |
82dcba
|
297 |
|
CM |
298 |
Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`. |
|
299 |
|
|
300 |
Extensible templating |
|
301 |
~~~~~~~~~~~~~~~~~~~~~ |
|
302 |
|
|
303 |
Pyramid has a structured API that allows for pluggability of "renderers". |
|
304 |
Templating systems such as Mako, Genshi, Chameleon, and Jinja2 can be treated |
|
305 |
as renderers. Renderer bindings for all of these templating systems already |
|
306 |
exist for use in Pyramid. But if you'd rather use another, it's not a big |
|
307 |
deal. Just copy the code from an existing renderer package, and plug in your |
ca00fb
|
308 |
favorite templating system. You'll then be able to use that templating system |
SP |
309 |
from within Pyramid just as you'd use one of the "built-in" templating systems. |
82dcba
|
310 |
|
ca00fb
|
311 |
Pyramid does not make you use a single templating system exclusively. You can |
SP |
312 |
use multiple templating systems, even in the same project. |
82dcba
|
313 |
|
CM |
314 |
Example: :ref:`templates_used_directly`. |
|
315 |
|
85ac6b
|
316 |
Rendered views can return dictionaries |
CM |
317 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
e08844
|
318 |
|
CM |
319 |
If you use a :term:`renderer`, you don't have to return a special kind of |
ca00fb
|
320 |
"webby" ``Response`` object from a view. Instead you can return a dictionary, |
SP |
321 |
and Pyramid will take care of converting that dictionary to a Response using a |
|
322 |
template on your behalf. This makes the view easier to test, because you don't |
|
323 |
have to parse HTML in your tests. Instead just make an assertion that the view |
|
324 |
returns "the right stuff" in the dictionary. You can write "real" unit tests |
|
325 |
instead of functionally testing all of your views. |
85ac6b
|
326 |
|
1f7a00
|
327 |
.. index:: |
KOP |
328 |
pair: renderer; explicitly calling |
|
329 |
pair: view renderer; explictly calling |
|
330 |
|
|
331 |
.. _example_render_to_response_call: |
|
332 |
|
|
333 |
For example, instead of returning a ``Response`` object from a |
|
334 |
``render_to_response`` call: |
85ac6b
|
335 |
|
CM |
336 |
.. code-block:: python |
392a6c
|
337 |
:linenos: |
85ac6b
|
338 |
|
CM |
339 |
from pyramid.renderers import render_to_response |
|
340 |
|
|
341 |
def myview(request): |
|
342 |
return render_to_response('myapp:templates/mytemplate.pt', {'a':1}, |
|
343 |
request=request) |
|
344 |
|
1f7a00
|
345 |
You can return a Python dictionary: |
85ac6b
|
346 |
|
CM |
347 |
.. code-block:: python |
392a6c
|
348 |
:linenos: |
85ac6b
|
349 |
|
CM |
350 |
from pyramid.view import view_config |
|
351 |
|
|
352 |
@view_config(renderer='myapp:templates/mytemplate.pt') |
|
353 |
def myview(request): |
|
354 |
return {'a':1} |
e08844
|
355 |
|
d10aeb
|
356 |
When this view callable is called by Pyramid, the ``{'a':1}`` dictionary will |
CM |
357 |
be rendered to a response on your behalf. The string passed as ``renderer=`` |
|
358 |
above is an :term:`asset specification`. It is in the form |
c946fc
|
359 |
``packagename:directoryname/filename.ext``. In this case, it refers to the |
d10aeb
|
360 |
``mytemplate.pt`` file in the ``templates`` directory within the ``myapp`` |
ca00fb
|
361 |
Python package. Asset specifications are omnipresent in Pyramid. See |
d10aeb
|
362 |
:ref:`intro_asset_specs` for more information. |
CM |
363 |
|
e08844
|
364 |
Example: :ref:`renderers_chapter`. |
CM |
365 |
|
82dcba
|
366 |
Event system |
CM |
367 |
~~~~~~~~~~~~ |
bb93cb
|
368 |
|
82dcba
|
369 |
Pyramid emits *events* during its request processing lifecycle. You can |
ca00fb
|
370 |
subscribe any number of listeners to these events. For example, to be notified |
SP |
371 |
of a new request, you can subscribe to the ``NewRequest`` event. To be |
|
372 |
notified that a template is about to be rendered, you can subscribe to the |
82dcba
|
373 |
``BeforeRender`` event, and so forth. Using an event publishing system as a |
CM |
374 |
framework notification feature instead of hardcoded hook points tends to make |
|
375 |
systems based on that framework less brittle. |
bb93cb
|
376 |
|
82dcba
|
377 |
You can also use Pyramid's event system to send your *own* events. For |
CM |
378 |
example, if you'd like to create a system that is itself a framework, and may |
|
379 |
want to notify subscribers that a document has just been indexed, you can |
ca00fb
|
380 |
create your own event type (``DocumentIndexed`` perhaps) and send the event via |
SP |
381 |
Pyramid. Users of this framework can then subscribe to your event like they'd |
|
382 |
subscribe to the events that are normally sent by Pyramid itself. |
970b88
|
383 |
|
82dcba
|
384 |
Example: :ref:`events_chapter` and :ref:`event_types`. |
CM |
385 |
|
|
386 |
Built-in internationalization |
|
387 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
388 |
|
0e5e1b
|
389 |
Pyramid ships with internationalization-related features in its core: |
82dcba
|
390 |
localization, pluralization, and creating message catalogs from source files |
d59239
|
391 |
and templates. Pyramid allows for a plurality of message catalogs via the use |
ca00fb
|
392 |
of translation domains. You can create a system that has its own translations |
82dcba
|
393 |
without conflict with other translations in other domains. |
CM |
394 |
|
|
395 |
Example: :ref:`i18n_chapter`. |
|
396 |
|
|
397 |
HTTP caching |
|
398 |
~~~~~~~~~~~~ |
|
399 |
|
ca00fb
|
400 |
Pyramid provides an easy way to associate views with HTTP caching policies. You |
SP |
401 |
can just tell Pyramid to configure your view with an ``http_cache`` statement, |
|
402 |
and it will take care of the rest:: |
82dcba
|
403 |
|
CM |
404 |
@view_config(http_cache=3600) # 60 minutes |
|
405 |
def myview(request): .... |
|
406 |
|
|
407 |
Pyramid will add appropriate ``Cache-Control`` and ``Expires`` headers to |
|
408 |
responses generated when this view is invoked. |
|
409 |
|
ca00fb
|
410 |
See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` |
SP |
411 |
documentation for more information. |
82dcba
|
412 |
|
CM |
413 |
Sessions |
|
414 |
~~~~~~~~ |
|
415 |
|
|
416 |
Pyramid has built-in HTTP sessioning. This allows you to associate data with |
|
417 |
otherwise anonymous users between requests. Lots of systems do this. But |
200417
|
418 |
Pyramid also allows you to plug in your own sessioning system by creating some |
KOP |
419 |
code that adheres to a documented interface. Currently there is a binding |
ca00fb
|
420 |
package for the third-party Redis sessioning system that does exactly this. But |
SP |
421 |
if you have a specialized need (perhaps you want to store your session data in |
|
422 |
MongoDB), you can. You can even switch between implementations without |
200417
|
423 |
changing your application code. |
82dcba
|
424 |
|
CM |
425 |
Example: :ref:`sessions_chapter`. |
|
426 |
|
|
427 |
Speed |
|
428 |
~~~~~ |
|
429 |
|
ca00fb
|
430 |
The Pyramid core is, as far as we can tell, at least marginally faster than any |
SP |
431 |
other existing Python web framework. It has been engineered from the ground up |
|
432 |
for speed. It only does as much work as absolutely necessary when you ask it |
|
433 |
to get a job done. Extraneous function calls and suboptimal algorithms in its |
|
434 |
core codepaths are avoided. It is feasible to get, for example, between 3500 |
|
435 |
and 4000 requests per second from a simple Pyramid view on commodity dual-core |
|
436 |
laptop hardware and an appropriate WSGI server (mod_wsgi or gunicorn). In any |
|
437 |
case, performance statistics are largely useless without requirements and |
|
438 |
goals, but if you need speed, Pyramid will almost certainly never be your |
|
439 |
application's bottleneck; at least no more than Python will be a bottleneck. |
82dcba
|
440 |
|
d59239
|
441 |
Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html |
82dcba
|
442 |
|
CM |
443 |
Exception views |
|
444 |
~~~~~~~~~~~~~~~ |
|
445 |
|
|
446 |
Exceptions happen. Rather than deal with exceptions that might present |
|
447 |
themselves to a user in production in an ad-hoc way, Pyramid allows you to |
|
448 |
register an :term:`exception view`. Exception views are like regular Pyramid |
|
449 |
views, but they're only invoked when an exception "bubbles up" to Pyramid |
|
450 |
itself. For example, you might register an exception view for the |
|
451 |
:exc:`Exception` exception, which will catch *all* exceptions, and present a |
|
452 |
pretty "well, this is embarrassing" page. Or you might choose to register an |
ca00fb
|
453 |
exception view for only specific kinds of application-specific exceptions, such |
SP |
454 |
as an exception that happens when a file is not found, or an exception that |
|
455 |
happens when an action cannot be performed because the user doesn't have |
82dcba
|
456 |
permission to do something. In the former case, you can show a pretty "Not |
CM |
457 |
Found" page; in the latter case you might show a login form. |
|
458 |
|
|
459 |
Example: :ref:`exception_views`. |
|
460 |
|
|
461 |
No singletons |
|
462 |
~~~~~~~~~~~~~ |
|
463 |
|
|
464 |
Pyramid is written in such a way that it requires your application to have |
ca00fb
|
465 |
exactly zero "singleton" data structures. Or put another way, Pyramid doesn't |
SP |
466 |
require you to construct any "mutable globals". Or put even another different |
|
467 |
way, an import of a Pyramid application needn't have any "import-time side |
|
468 |
effects". This is esoteric-sounding, but if you've ever tried to cope with |
|
469 |
parameterizing a Django ``settings.py`` file for multiple installations of the |
|
470 |
same application, or if you've ever needed to monkey-patch some framework |
|
471 |
fixture so that it behaves properly for your use case, or if you've ever wanted |
|
472 |
to deploy your system using an asynchronous server, you'll end up appreciating |
|
473 |
this feature. It just won't be a problem. You can even run multiple copies of |
|
474 |
a similar but not identically configured Pyramid application within the same |
|
475 |
Python process. This is good for shared hosting environments, where RAM is at |
|
476 |
a premium. |
82dcba
|
477 |
|
CM |
478 |
View predicates and many views per route |
|
479 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
480 |
|
|
481 |
Unlike many other systems, Pyramid allows you to associate more than one view |
ca00fb
|
482 |
per route. For example, you can create a route with the pattern ``/items`` and |
SP |
483 |
when the route is matched, you can shuffle off the request to one view if the |
|
484 |
request method is GET, another view if the request method is POST, etc. A |
|
485 |
system known as "view predicates" allows for this. Request method matching is |
|
486 |
the most basic thing you can do with a view predicate. You can also associate |
|
487 |
views with other request parameters, such as the elements in the query string, |
|
488 |
the Accept header, whether the request is an XHR request or not, and lots of |
|
489 |
other things. This feature allows you to keep your individual views clean. |
|
490 |
They won't need much conditional logic, so they'll be easier to test. |
82dcba
|
491 |
|
CM |
492 |
Example: :ref:`view_configuration_parameters`. |
|
493 |
|
|
494 |
Transaction management |
|
495 |
~~~~~~~~~~~~~~~~~~~~~~ |
|
496 |
|
ca00fb
|
497 |
Pyramid's :term:`scaffold` system renders projects that include a *transaction |
SP |
498 |
management* system, stolen from Zope. When you use this transaction management |
|
499 |
system, you cease being responsible for committing your data anymore. Instead |
|
500 |
Pyramid takes care of committing: it commits at the end of a request or aborts |
|
501 |
if there's an exception. Why is that a good thing? Having a centralized place |
|
502 |
for transaction management is a great thing. If, instead of managing your |
|
503 |
transactions in a centralized place, you sprinkle ``session.commit`` calls in |
|
504 |
your application logic itself, you can wind up in a bad place. Wherever you |
|
505 |
manually commit data to your database, it's likely that some of your other code |
|
506 |
is going to run *after* your commit. If that code goes on to do other important |
|
507 |
things after that commit, and an error happens in the later code, you can |
|
508 |
easily wind up with inconsistent data if you're not extremely careful. Some |
|
509 |
data will have been written to the database that probably should not have. |
|
510 |
Having a centralized commit point saves you from needing to think about this; |
|
511 |
it's great for lazy people who also care about data integrity. Either the |
|
512 |
request completes successfully, and all changes are committed, or it does not, |
|
513 |
and all changes are aborted. |
82dcba
|
514 |
|
ca00fb
|
515 |
Pyramid's transaction management system allows you to synchronize commits |
SP |
516 |
between multiple databases. It also allows you to do things like conditionally |
|
517 |
send email if a transaction commits, but otherwise keep quiet. |
82dcba
|
518 |
|
CM |
519 |
Example: :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements |
|
520 |
anywhere in application code). |
|
521 |
|
|
522 |
Configuration conflict detection |
|
523 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
524 |
|
ca00fb
|
525 |
When a system is small, it's reasonably easy to keep it all in your head. But |
SP |
526 |
when systems grow large, you may have hundreds or thousands of configuration |
|
527 |
statements which add a view, add a route, and so forth. |
d59239
|
528 |
|
ca00fb
|
529 |
Pyramid's configuration system keeps track of your configuration statements. If |
SP |
530 |
you accidentally add two that are identical, or Pyramid can't make sense out of |
|
531 |
what it would mean to have both statements active at the same time, it will |
|
532 |
complain loudly at startup time. It's not dumb though. It will automatically |
|
533 |
resolve conflicting configuration statements on its own if you use the |
|
534 |
configuration :meth:`~pyramid.config.Configurator.include` system. "More local" |
|
535 |
statements are preferred over "less local" ones. This allows you to |
|
536 |
intelligently factor large systems into smaller ones. |
82dcba
|
537 |
|
CM |
538 |
Example: :ref:`conflict_detection`. |
|
539 |
|
|
540 |
Configuration extensibility |
|
541 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
542 |
|
|
543 |
Unlike other systems, Pyramid provides a structured "include" mechanism (see |
1d03bb
|
544 |
:meth:`~pyramid.config.Configurator.include`) that allows you to combine |
82dcba
|
545 |
applications from multiple Python packages. All the configuration statements |
ca00fb
|
546 |
that can be performed in your "main" Pyramid application can also be performed |
SP |
547 |
by included packages, including the addition of views, routes, subscribers, and |
|
548 |
even authentication and authorization policies. You can even extend or override |
|
549 |
an existing application by including another application's configuration in |
|
550 |
your own, overriding or adding new views and routes to it. This has the |
|
551 |
potential to allow you to create a big application out of many other smaller |
|
552 |
ones. For example, if you want to reuse an existing application that already |
|
553 |
has a bunch of routes, you can just use the ``include`` statement with a |
|
554 |
``route_prefix``. The new application will live within your application at an |
|
555 |
URL prefix. It's not a big deal, and requires little up-front engineering |
|
556 |
effort. |
82dcba
|
557 |
|
CM |
558 |
For example: |
|
559 |
|
|
560 |
.. code-block:: python |
|
561 |
:linenos: |
|
562 |
|
|
563 |
from pyramid.config import Configurator |
|
564 |
|
|
565 |
if __name__ == '__main__': |
|
566 |
config = Configurator() |
|
567 |
config.include('pyramid_jinja2') |
|
568 |
config.include('pyramid_exclog') |
|
569 |
config.include('some.other.guys.package', route_prefix='/someotherguy') |
|
570 |
|
2033ee
|
571 |
.. seealso:: |
SP |
572 |
|
|
573 |
See also :ref:`including_configuration` and |
|
574 |
:ref:`building_an_extensible_app`. |
82dcba
|
575 |
|
CM |
576 |
Flexible authentication and authorization |
|
577 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
578 |
|
ca00fb
|
579 |
Pyramid includes a flexible, pluggable authentication and authorization system. |
SP |
580 |
No matter where your user data is stored, or what scheme you'd like to use to |
|
581 |
permit your users to access your data, you can use a predefined Pyramid |
|
582 |
plugpoint to plug in your custom authentication and authorization code. If you |
|
583 |
want to change these schemes later, you can just change it in one place rather |
|
584 |
than everywhere in your code. It also ships with prebuilt well-tested |
|
585 |
authentication and authorization schemes out of the box. But what if you don't |
|
586 |
want to use Pyramid's built-in system? You don't have to. You can just write |
|
587 |
your own bespoke security code as you would in any other system. |
82dcba
|
588 |
|
CM |
589 |
Example: :ref:`enabling_authorization_policy`. |
|
590 |
|
|
591 |
Traversal |
|
592 |
~~~~~~~~~ |
|
593 |
|
|
594 |
:term:`Traversal` is a concept stolen from :term:`Zope`. It allows you to |
ca00fb
|
595 |
create a tree of resources, each of which can be addressed by one or more URLs. |
SP |
596 |
Each of those resources can have one or more *views* associated with it. If |
|
597 |
your data isn't naturally treelike, or you're unwilling to create a treelike |
|
598 |
representation of your data, you aren't going to find traversal very useful. |
|
599 |
However, traversal is absolutely fantastic for sites that need to be |
|
600 |
arbitrarily extensible. It's a lot easier to add a node to a tree than it is to |
|
601 |
shoehorn a route into an ordered list of other routes, or to create another |
|
602 |
entire instance of an application to service a department and glue code to |
|
603 |
allow disparate apps to share data. It's a great fit for sites that naturally |
|
604 |
lend themselves to changing departmental hierarchies, such as content |
|
605 |
management systems and document management systems. Traversal also lends |
|
606 |
itself well to systems that require very granular security ("Bob can edit |
|
607 |
*this* document" as opposed to "Bob can edit documents"). |
82dcba
|
608 |
|
d6a954
|
609 |
Examples: :ref:`hello_traversal_chapter` and |
CM |
610 |
:ref:`much_ado_about_traversal_chapter`. |
82dcba
|
611 |
|
CM |
612 |
Tweens |
|
613 |
~~~~~~ |
|
614 |
|
37607c
|
615 |
Pyramid has a sort of internal WSGI-middleware-ish pipeline that can be hooked |
CI |
616 |
by arbitrary add-ons named "tweens". The debug toolbar is a "tween", and the |
|
617 |
``pyramid_tm`` transaction manager is also. Tweens are more useful than WSGI |
|
618 |
:term:`middleware` in some circumstances because they run in the context of |
82dcba
|
619 |
Pyramid itself, meaning you have access to templates and other renderers, a |
CM |
620 |
"real" request object, and other niceties. |
|
621 |
|
|
622 |
Example: :ref:`registering_tweens`. |
bb93cb
|
623 |
|
d3aae8
|
624 |
View response adapters |
970b88
|
625 |
~~~~~~~~~~~~~~~~~~~~~~ |
85ac6b
|
626 |
|
970b88
|
627 |
A lot is made of the aesthetics of what *kinds* of objects you're allowed to |
CM |
628 |
return from view callables in various frameworks. In a previous section in |
d59239
|
629 |
this document, we showed you that, if you use a :term:`renderer`, you can |
970b88
|
630 |
usually return a dictionary from a view callable instead of a full-on |
814455
|
631 |
:term:`Response` object. But some frameworks allow you to return strings or |
e7085b
|
632 |
tuples from view callables. When frameworks allow for this, code looks |
CM |
633 |
slightly prettier, because fewer imports need to be done, and there is less |
|
634 |
code. For example, compare this: |
85ac6b
|
635 |
|
CM |
636 |
.. code-block:: python |
|
637 |
:linenos: |
|
638 |
|
|
639 |
def aview(request): |
|
640 |
return "Hello world!" |
|
641 |
|
|
642 |
To this: |
|
643 |
|
|
644 |
.. code-block:: python |
|
645 |
:linenos: |
|
646 |
|
|
647 |
from pyramid.response import Response |
|
648 |
|
|
649 |
def aview(request): |
|
650 |
return Response("Hello world!") |
|
651 |
|
|
652 |
The former is "prettier", right? |
|
653 |
|
|
654 |
Out of the box, if you define the former view callable (the one that simply |
|
655 |
returns a string) in Pyramid, when it is executed, Pyramid will raise an |
ca00fb
|
656 |
exception. This is because "explicit is better than implicit", in most cases, |
SP |
657 |
and by default Pyramid wants you to return a :term:`Response` object from a |
|
658 |
view callable. This is because there's usually a heck of a lot more to a |
|
659 |
response object than just its body. But if you're the kind of person who |
|
660 |
values such aesthetics, we have an easy way to allow for this sort of thing: |
85ac6b
|
661 |
|
CM |
662 |
.. code-block:: python |
|
663 |
:linenos: |
|
664 |
|
|
665 |
from pyramid.config import Configurator |
|
666 |
from pyramid.response import Response |
|
667 |
|
|
668 |
def string_response_adapter(s): |
|
669 |
response = Response(s) |
|
670 |
response.content_type = 'text/html' |
|
671 |
return response |
|
672 |
|
|
673 |
if __name__ == '__main__': |
|
674 |
config = Configurator() |
|
675 |
config.add_response_adapter(string_response_adapter, basestring) |
|
676 |
|
|
677 |
Do that once in your Pyramid application at startup. Now you can return |
|
678 |
strings from any of your view callables, e.g.: |
|
679 |
|
|
680 |
.. code-block:: python |
|
681 |
:linenos: |
|
682 |
|
|
683 |
def helloview(request): |
|
684 |
return "Hello world!" |
|
685 |
|
|
686 |
def goodbyeview(request): |
|
687 |
return "Goodbye world!" |
|
688 |
|
|
689 |
Oh noes! What if you want to indicate a custom content type? And a custom |
|
690 |
status code? No fear: |
|
691 |
|
|
692 |
.. code-block:: python |
|
693 |
:linenos: |
|
694 |
|
|
695 |
from pyramid.config import Configurator |
|
696 |
|
|
697 |
def tuple_response_adapter(val): |
|
698 |
status_int, content_type, body = val |
|
699 |
response = Response(body) |
|
700 |
response.content_type = content_type |
|
701 |
response.status_int = status_int |
|
702 |
return response |
|
703 |
|
|
704 |
def string_response_adapter(body): |
|
705 |
response = Response(body) |
|
706 |
response.content_type = 'text/html' |
|
707 |
response.status_int = 200 |
|
708 |
return response |
|
709 |
|
|
710 |
if __name__ == '__main__': |
|
711 |
config = Configurator() |
|
712 |
config.add_response_adapter(string_response_adapter, basestring) |
|
713 |
config.add_response_adapter(tuple_response_adapter, tuple) |
|
714 |
|
|
715 |
Once this is done, both of these view callables will work: |
|
716 |
|
|
717 |
.. code-block:: python |
|
718 |
:linenos: |
|
719 |
|
|
720 |
def aview(request): |
|
721 |
return "Hello world!" |
|
722 |
|
|
723 |
def anotherview(request): |
|
724 |
return (403, 'text/plain', "Forbidden") |
|
725 |
|
ca00fb
|
726 |
Pyramid defaults to explicit behavior, because it's the most generally useful, |
SP |
727 |
but provides hooks that allow you to adapt the framework to localized aesthetic |
|
728 |
desires. |
85ac6b
|
729 |
|
2033ee
|
730 |
.. seealso:: |
SP |
731 |
|
|
732 |
See also :ref:`using_iresponse`. |
85ac6b
|
733 |
|
d3aae8
|
734 |
"Global" response object |
970b88
|
735 |
~~~~~~~~~~~~~~~~~~~~~~~~ |
CM |
736 |
|
ca00fb
|
737 |
"Constructing these response objects in my view callables is such a chore! And |
SP |
738 |
I'm way too lazy to register a response adapter, as per the prior section," you |
|
739 |
say. Fine. Be that way: |
970b88
|
740 |
|
CM |
741 |
.. code-block:: python |
|
742 |
:linenos: |
|
743 |
|
|
744 |
def aview(request): |
|
745 |
response = request.response |
|
746 |
response.body = 'Hello world!' |
|
747 |
response.content_type = 'text/plain' |
|
748 |
return response |
|
749 |
|
2033ee
|
750 |
.. seealso:: |
SP |
751 |
|
|
752 |
See also :ref:`request_response_attr`. |
bb93cb
|
753 |
|
214125
|
754 |
Automating repetitive configuration |
CM |
755 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
756 |
|
|
757 |
Does Pyramid's configurator allow you to do something, but you're a little |
ca00fb
|
758 |
adventurous and just want it a little less verbose? Or you'd like to offer up |
SP |
759 |
some handy configuration feature to other Pyramid users without requiring that |
|
760 |
we change Pyramid? You can extend Pyramid's :term:`Configurator` with your own |
|
761 |
directives. For example, let's say you find yourself calling |
214125
|
762 |
:meth:`pyramid.config.Configurator.add_view` repetitively. Usually you can |
ca00fb
|
763 |
take the boring away by using existing shortcuts, but let's say that this is a |
SP |
764 |
case where there is no such shortcut: |
214125
|
765 |
|
CM |
766 |
.. code-block:: python |
|
767 |
:linenos: |
|
768 |
|
|
769 |
from pyramid.config import Configurator |
|
770 |
|
|
771 |
config = Configurator() |
|
772 |
config.add_route('xhr_route', '/xhr/{id}') |
|
773 |
config.add_view('my.package.GET_view', route_name='xhr_route', |
|
774 |
xhr=True, permission='view', request_method='GET') |
|
775 |
config.add_view('my.package.POST_view', route_name='xhr_route', |
|
776 |
xhr=True, permission='view', request_method='POST') |
|
777 |
config.add_view('my.package.HEAD_view', route_name='xhr_route', |
|
778 |
xhr=True, permission='view', request_method='HEAD') |
|
779 |
|
|
780 |
Pretty tedious right? You can add a directive to the Pyramid configurator to |
|
781 |
automate some of the tedium away: |
|
782 |
|
|
783 |
.. code-block:: python |
|
784 |
:linenos: |
|
785 |
|
|
786 |
from pyramid.config import Configurator |
|
787 |
|
|
788 |
def add_protected_xhr_views(config, module): |
|
789 |
module = config.maybe_dotted(module) |
|
790 |
for method in ('GET', 'POST', 'HEAD'): |
|
791 |
view = getattr(module, 'xhr_%s_view' % method, None) |
|
792 |
if view is not None: |
d84407
|
793 |
config.add_view(view, route_name='xhr_route', xhr=True, |
214125
|
794 |
permission='view', request_method=method) |
CM |
795 |
|
|
796 |
config = Configurator() |
|
797 |
config.add_directive('add_protected_xhr_views', add_protected_xhr_views) |
|
798 |
|
|
799 |
Once that's done, you can call the directive you've just added as a method of |
|
800 |
the Configurator object: |
|
801 |
|
|
802 |
.. code-block:: python |
|
803 |
:linenos: |
|
804 |
|
|
805 |
config.add_route('xhr_route', '/xhr/{id}') |
|
806 |
config.add_protected_xhr_views('my.package') |
|
807 |
|
|
808 |
Your previously repetitive configuration lines have now morphed into one line. |
|
809 |
|
ca00fb
|
810 |
You can share your configuration code with others this way, too, by packaging |
214125
|
811 |
it up and calling :meth:`~pyramid.config.Configurator.add_directive` from |
CM |
812 |
within a function called when another user uses the |
|
813 |
:meth:`~pyramid.config.Configurator.include` method against your code. |
|
814 |
|
2033ee
|
815 |
.. seealso:: |
SP |
816 |
|
|
817 |
See also :ref:`add_directive`. |
214125
|
818 |
|
d59239
|
819 |
Programmatic introspection |
321785
|
820 |
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
5d0989
|
821 |
|
CM |
822 |
If you're building a large system that other users may plug code into, it's |
|
823 |
useful to be able to get an enumeration of what code they plugged in *at |
|
824 |
application runtime*. For example, you might want to show them a set of tabs |
|
825 |
at the top of the screen based on an enumeration of views they registered. |
|
826 |
|
|
827 |
This is possible using Pyramid's :term:`introspector`. |
|
828 |
|
ca00fb
|
829 |
Here's an example of using Pyramid's introspector from within a view callable: |
5d0989
|
830 |
|
CM |
831 |
.. code-block:: python |
392a6c
|
832 |
:linenos: |
5d0989
|
833 |
|
CM |
834 |
from pyramid.view import view_config |
|
835 |
from pyramid.response import Response |
|
836 |
|
|
837 |
@view_config(route_name='bar') |
|
838 |
def show_current_route_pattern(request): |
|
839 |
introspector = request.registry.introspector |
|
840 |
route_name = request.matched_route.name |
|
841 |
route_intr = introspector.get('routes', route_name) |
|
842 |
return Response(str(route_intr['pattern'])) |
|
843 |
|
2033ee
|
844 |
.. seealso:: |
SP |
845 |
|
|
846 |
See also :ref:`using_introspection`. |
5d0989
|
847 |
|
d59239
|
848 |
Python 3 compatibility |
321785
|
849 |
~~~~~~~~~~~~~~~~~~~~~~ |
1252ab
|
850 |
|
CM |
851 |
Pyramid and most of its add-ons are Python 3 compatible. If you develop a |
|
852 |
Pyramid application today, you won't need to worry that five years from now |
ca00fb
|
853 |
you'll be backwatered because there are language features you'd like to use but |
SP |
854 |
your framework doesn't support newer Python versions. |
1252ab
|
855 |
|
bb93cb
|
856 |
Testing |
CM |
857 |
~~~~~~~ |
|
858 |
|
|
859 |
Every release of Pyramid has 100% statement coverage via unit and integration |
|
860 |
tests, as measured by the ``coverage`` tool available on PyPI. It also has |
|
861 |
greater than 95% decision/condition coverage as measured by the |
682ca5
|
862 |
``instrumental`` tool available on PyPI. It is automatically tested by Travis, |
c8a5e0
|
863 |
and Jenkins on Python 2.7, Python 3.4, Python 3.5, Python 3.6, and PyPy |
682ca5
|
864 |
after each commit to its GitHub repository. Official Pyramid add-ons are held |
BJR |
865 |
to a similar testing standard. We still find bugs in Pyramid and its official |
|
866 |
add-ons, but we've noticed we find a lot more of them while working on other |
|
867 |
projects that don't have a good testing regime. |
bb93cb
|
868 |
|
682ca5
|
869 |
Travis: https://travis-ci.org/Pylons/pyramid |
BJR |
870 |
Jenkins: http://jenkins.pylonsproject.org/job/pyramid/ |
bb93cb
|
871 |
|
CM |
872 |
Support |
|
873 |
~~~~~~~ |
|
874 |
|
|
875 |
It's our goal that no Pyramid question go unanswered. Whether you ask a |
d59239
|
876 |
question on IRC, on the Pylons-discuss mailing list, or on StackOverflow, |
SP |
877 |
you're likely to get a reasonably prompt response. We don't tolerate "support |
bdebfb
|
878 |
trolls" or other people who seem to get their rocks off by berating fellow |
ca00fb
|
879 |
users in our various official support channels. We try to keep it well-lit and |
SP |
880 |
new-user-friendly. |
bb93cb
|
881 |
|
c8b363
|
882 |
Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on |
bb93cb
|
883 |
irc.freenode.net in an IRC client) or the pylons-discuss maillist at |
1cb30e
|
884 |
https://groups.google.com/forum/#!forum/pylons-discuss. |
bb93cb
|
885 |
|
CM |
886 |
Documentation |
|
887 |
~~~~~~~~~~~~~ |
|
888 |
|
ca00fb
|
889 |
It's a constant struggle, but we try to maintain a balance between completeness |
SP |
890 |
and new-user-friendliness in the official narrative Pyramid documentation |
|
891 |
(concrete suggestions for improvement are always appreciated, by the way). We |
|
892 |
also maintain a "cookbook" of recipes, which are usually demonstrations of |
|
893 |
common integration scenarios too specific to add to the official narrative |
|
894 |
docs. In any case, the Pyramid documentation is comprehensive. |
bb93cb
|
895 |
|
34515f
|
896 |
Example: The :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>`. |
bb93cb
|
897 |
|
3ea7c7
|
898 |
.. index:: |
6ce1e0
|
899 |
single: Pylons Project |
3ea7c7
|
900 |
|
a3a27a
|
901 |
What Is The Pylons Project? |
CM |
902 |
--------------------------- |
3ea7c7
|
903 |
|
fd5ae9
|
904 |
:app:`Pyramid` is a member of the collection of software published under the |
c06d4a
|
905 |
Pylons Project. Pylons software is written by a loose-knit community of |
1cb30e
|
906 |
contributors. The `Pylons Project website <http://www.pylonsproject.org>`_ |
fd5ae9
|
907 |
includes details about how :app:`Pyramid` relates to the Pylons Project. |
093628
|
908 |
|
8c56ae
|
909 |
.. index:: |
fec0f0
|
910 |
single: pyramid and other frameworks |
e0887e
|
911 |
single: Zope |
CM |
912 |
single: Pylons |
|
913 |
single: Django |
|
914 |
single: MVC |
8c56ae
|
915 |
|
fd5ae9
|
916 |
:app:`Pyramid` and Other Web Frameworks |
9ec2d6
|
917 |
------------------------------------------ |
9e3bdb
|
918 |
|
7a505d
|
919 |
The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made |
ca00fb
|
920 |
in July of 2008. At the end of 2010, we changed the name of :mod:`repoze.bfg` |
SP |
921 |
to :app:`Pyramid`. It was merged into the Pylons project as :app:`Pyramid` in |
|
922 |
November of that year. |
fec0f0
|
923 |
|
ca00fb
|
924 |
:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version 1.0), and |
SP |
925 |
:term:`Django`. As a result, :app:`Pyramid` borrows several concepts and |
|
926 |
features from each, combining them into a unique web framework. |
878328
|
927 |
|
ca00fb
|
928 |
Many features of :app:`Pyramid` trace their origins back to :term:`Zope`. Like |
SP |
929 |
Zope applications, :app:`Pyramid` applications can be easily extended. If you |
|
930 |
obey certain constraints, the application you produce can be reused, modified, |
|
931 |
re-integrated, or extended by third-party developers without forking the |
|
932 |
original application. The concepts of :term:`traversal` and declarative |
|
933 |
security in :app:`Pyramid` were pioneered first in Zope. |
601289
|
934 |
|
fd5ae9
|
935 |
The :app:`Pyramid` concept of :term:`URL dispatch` is inspired by the |
d59239
|
936 |
:term:`Routes` system used by :term:`Pylons` version 1.0. Like Pylons version |
SP |
937 |
1.0, :app:`Pyramid` is mostly policy-free. It makes no assertions about which |
|
938 |
database you should use. Pyramid no longer has built-in templating facilities |
|
939 |
as of version 1.5a2, but instead officially supports bindings for templating |
ca00fb
|
940 |
languages, including Chameleon, Jinja2, and Mako. In essence, it only supplies |
SP |
941 |
a mechanism to map URLs to :term:`view` code, along with a set of conventions |
|
942 |
for calling those views. You are free to use third-party components that fit |
|
943 |
your needs in your applications. |
601289
|
944 |
|
ca00fb
|
945 |
The concept of :term:`view` is used by :app:`Pyramid` mostly as it would be by |
SP |
946 |
Django. :app:`Pyramid` has a documentation culture more like Django's than |
|
947 |
like Zope's. |
52ced0
|
948 |
|
7a505d
|
949 |
Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a :app:`Pyramid` |
CM |
950 |
application developer may use completely imperative code to perform common |
|
951 |
framework configuration tasks such as adding a view or a route. In Zope, |
|
952 |
:term:`ZCML` is typically required for similar purposes. In :term:`Grok`, a |
|
953 |
Zope-based web framework, :term:`decorator` objects and class-level |
55ce9d
|
954 |
declarations are used for this purpose. Out of the box, Pyramid supports |
ca00fb
|
955 |
imperative and decorator-based configuration. :term:`ZCML` may be used via an |
55ce9d
|
956 |
add-on package named ``pyramid_zcml``. |
c0c188
|
957 |
|
ca00fb
|
958 |
Also unlike :term:`Zope` and other "full-stack" frameworks such as |
SP |
959 |
:term:`Django`, :app:`Pyramid` makes no assumptions about which persistence |
|
960 |
mechanisms you should use to build an application. Zope applications are |
|
961 |
typically reliant on :term:`ZODB`. :app:`Pyramid` allows you to build |
|
962 |
:term:`ZODB` applications, but it has no reliance on the ZODB software. |
|
963 |
Likewise, :term:`Django` tends to assume that you want to store your |
|
964 |
application's data in a relational database. :app:`Pyramid` makes no such |
|
965 |
assumption, allowing you to use a relational database, and neither encouraging |
|
966 |
nor discouraging the decision. |
a56d0c
|
967 |
|
ca00fb
|
968 |
Other Python web frameworks advertise themselves as members of a class of web |
SP |
969 |
frameworks named `model-view-controller |
1cb30e
|
970 |
<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_ |
SP |
971 |
frameworks. Insofar as this term has been claimed to represent a class of web |
|
972 |
frameworks, :app:`Pyramid` also generally fits into this class. |
c5f24b
|
973 |
|
ca00fb
|
974 |
.. sidebar:: You Say :app:`Pyramid` is MVC, but Where's the Controller? |
c5f24b
|
975 |
|
ca00fb
|
976 |
The :app:`Pyramid` authors believe that the MVC pattern just doesn't really |
SP |
977 |
fit the web very well. In a :app:`Pyramid` application, there is a resource |
|
978 |
tree which represents the site structure, and views which tend to present |
|
979 |
the data stored in the resource tree and a user-defined "domain model". |
|
980 |
However, no facility provided *by the framework* actually necessarily maps |
|
981 |
to the concept of a "controller" or "model". So if you had to give it some |
|
982 |
acronym, I guess you'd say :app:`Pyramid` is actually an "RV" framework |
|
983 |
rather than an "MVC" framework. "MVC", however, is close enough as a |
|
984 |
general classification moniker for purposes of comparison with other web |
|
985 |
frameworks. |