Latest Version: 0.9.6.2
  Dashboard > Pylons Official Docs > Home > Getting Started
  Pylons Official Docs Log In | Sign Up   View a printable version of the current page.  
  Getting Started
Added by James Gardner, last edited by Ches Martin on Dec 13, 2007  (view change) show comment
Labels: 
(None)

2   Creating a Pylons Project

Pylons uses Paste to create and deploy projects as well as create new controllers and their tests.

Create a new project named helloworld with this command:

1
$ paster create -t pylons helloworld

Note: Windows users must configure their PATH as described in Windows Notes, otherwise they must specify the full path name to the paster command.

This creates a new Pylons project which you can use as a basis for your own project. The directory structure is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
- helloworld
    - README.txt
    - data
    - docs
    - development.ini
    - helloworld
    - helloworld.egg-info
        - Various files including paste_deploy_config.ini_tmpl
    - setup.cfg
    - setup.py
    - test.ini

The setup.py file is used to create a re-distributable Python package of your project called an egg. Eggs can be thought of as similar to .jar files in Java. The setup.cfg file contains extra information about your project and the helloworld.egg-info directory contains information about the egg including a paste_deploy_config.ini_tmpl file which is used as a template for the config file when users of your project issue a paster make-config command. Distributing and deploying your egg is covered in the Distributing Your Project documentation and end user configuration is described in Application Setup.

You may also notice a data directory which is created the first time you run the code. You can configure the location of the data directory by editing your development.ini file. This directory will hold cached data and sessions used by your app while its running.

The helloworld directory within the helloworld directory is where all your application specific code and files are placed. The directory looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
- helloworld
    - helloworld
        - config
        - controllers
        - lib
        - model
        - public
        - templates
        - tests
        - __init__.py
        - websetup.py

The config directory contains the configuration options for your web application.

The controllers directory is where your application controllers are written. Controllers are the core of your application where the decision is made on what data to load, and how to view it.

The lib directory is where you can put code that is used between different controllers, third party code, or any other code that doesn't fit in well elsewhere.

The model directory is for your model objects, if you're using an ORM this is where the classes for them should go. Objects defined in model/__init__.py will be loaded and present as model.YourObject inside your controllers. The database configuration string can be set in your development.ini file.

The public directory is where you put all your HTML, images, Javascript, CSS and other static files. It is similar to the htdocs directory in Apache.

The tests directory is where you can put controller and other tests. The controller testing functionality uses Nose and paste.fixture.

The templates directory is where templates are stored. Templates contain a mixture of plain text and Python code and are used for creating HTML and other documents in a way that is easy for designers to tweak without them needing to see all the code that goes on behind the scenes. Pylons uses Mako templates by default but also supports Cheetah, Kid and others through a system called Buffet. See how to change template languages

The __init__.py file is present so that the helloworld directory can be used as a Python module within the egg.

The websetup.py should contain any code that should be executed when an end user of your application runs the paster setup-app command described in Application Setup. If you're looking for where to put that should be run before your application is, this is the place.

3   Testing the template project

We can test the template project like this:

1
2
$ cd helloworld
$ paster serve --reload development.ini

The command loads our project server configuration file in development.ini and serves the Pylons application.

The --reload option ensures that the server is automatically reloaded if you make any changes to Python files or the development.ini config file. This is very useful during development. To stop the server you can press Ctrl+c or your platform's equivalent.

If you visit http://127.0.0.1:5000/ when the server is running you will see the welcome page (127.0.0.1 is a special IP address that references your own computer but you can change the hostname by editing the development.ini file).

Try creating a new file named test.html in the helloworld/public directory with the following content:

1
2
3
4
5
<html>
    <body>
        Hello World!
    </body>
</html>

If you visit http://127.0.0.1:5000/test.html you will see the message Hello World!. Any files in the public directory are served in the same way they would be by any webserver, but with built-in caching, and if Pylons has a choice of whether to serve a file from the public directory or from code in a controller it will always choose the file in public. This behavior can be changed by altering the order of the Cascade in config/middleware.py.

4   Interactive Debugger

The interactive debugger is a powerful tool for use during application development. It is enabled by default in the development environment's development.ini. When enabled, it allows debugging of the application through a web page after an exception is raised. On production environments the debugger poses a major security risk; so production ini files generated from the paster make-config command will have debugging disabled.

To disable debugging, uncomment the following line in the [app:main] section of your development.ini:

1
#set debug = false

to:

1
set debug = false

Again; debug must be set to false on production environments as the interactive debugger poses a MAJOR SECURITY RISK.

More information is available in the Interactive Debugger documentation.

5   Creating a Controller and modifying the Routes

You're now ready to start creating your own web application. First, lets create a basic hello World controller:

1
$ paster controller hello

This paster command will create the controllers/hello.py file for you with a basic layout as well as a helloworld/tests/functional/test_hello.py that is used for running functional tests of the controller.

Here's what a basic controller looks like to print out 'Hello World' and respond to http://127.0.0.1:5000/hello. Put the following text in the file helloworld/controllers/hello.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import logging

from helloworld.lib.base import *

log = logging.getLogger(__name__)

class HelloController(BaseController):

    def index(self):
        # Return a rendered template
        #   return render('/some/template.mako')
        # or, Return a response
        return 'Hello World'

Pylons uses a powerful and flexible system for routing URLs to the appropriate piece of code and back.

We would like the hello controller to also be displayed for both the URL http://127.0.0.1:5000/hello and the URL http://127.0.0.1:5000/ which is the site route. We need to add a line to the routes config in helloworld/config/routing.py so it looks like this:

1
2
3
map.connect('', controller='hello', action='index')
map.connect(':controller/:action/:id')
map.connect('*url', controller='template', action='view')

This means that an empty URL is matched to the index action of the hello controller. Otherwise, the route mapper looks for URLs in the form controller/action/id, but if action or controller are not specified the request is routed to the view action of the templates controller (created by the Pylons template). This raises a 404 error by default.

Since we have made changes to our routes we must restart the server. If you are using the --reload option this will happen automatically, otherwise close the old server and start it again using the same command as before. (Note: Mako template changes do not require restarting the server even without the --reload option.)

Visit both http://127.0.0.1:5000/hello and http://127.0.0.1:5000/ and you will find that although the first URL produces the expected Hello World, the second URL produces the welcome page as before. This is because, as mentioned earlier, static files in the public directory are served before looking for code.

Delete the file public/index.html and the application works as expected.

More information on routes can be found in the Routes manual.

6   Templates and the Request Cycle

When your controller's action is called it is expected to either call a WSGI application or return a response. In the previous section we saw a basic example which returned a string response. To render templates, use the render command.

Note

For the gory details on the available options to render look at the Pylons templating API.

Here's an example template, using Mako, that prints some request information.

Create a template file helloworld/templates/serverinfo.mako containing the following:

1
2
3
4
5
6
7
<h2>
Server info for ${request.host}
</h2>

<p>
The URL you called: ${h.url_for()}
</p>

To use this template add a new method to your HelloController in helloworld/controllers/hello.py with the following function at the end of the class:

1
2
def serverinfo(self):
    return render('/serverinfo.mako')

The render('/serverinfo.mako') function will render your template using the default template engine (Mako).

If your server is still running you can view the page at: http://127.0.0.1:5000/hello/serverinfo

If not simply restart the server with paster serve --reload development.ini from the helloworld directory.

7   Using Sessions

Sessions come enabled for your application and are handled by the Beaker middleware. This provides robust and powerful sessions as well as caching abilities.

Using a session is very easy, here's what using and saving a session in the above function would look like:

1
2
3
4
def serverinfo(self):
    session['name'] = 'George'
    session.save()
    return render('/serverinfo.mako')

Session options can be customized via your development.ini file.

Note

Remember to always call session.save() before returning a response to ensure that the session is saved.

8   Controller Variables and Template Globals

8.1   Pylons Globals

For convenience, there are several globals (imported from lib.base) available for use in your controllers:

object description
session Acts as a dict to store session data.
request The request object
response The response object, headers, cookies and status code can be set on this which will be used for the response
abort Function to abort the request immediately by raising an HTTPException according to the specified status code
redirect_to Function to redirect the browser to a different location via the HTTP 302 status code (by raising an HTTPException)
render Function to render a template and return a string
h Your project's lib/helpers.py module. By default, this module exposes all functions available from the WebHelpers package. Keep in mind when reading the WebHelpers docs that all the functions listed should be prefixed by h. when used under Pylons.
c (described in Passing Variables to Templates)
g (described in Application Globals and Persistent Objects)
config Dictionary-like object for accessing .ini file directives and other Pylons configuration options.
cache, etag_cache Caching objects and functions. (described in the Caching in Templates and Controllers doc)
jsonify Action decorator to format output as JavaScript Object Notation.
validate Decorator for convenient form validation with FormEncode. (further described in the Form Handling document)
_, N_, ungettext Internationalization / localization functions. (described in the Internationalization and Localization doc)
model Access to your model package, however you choose to define it.

8.2   Passing Variables to Templates

Pylons controllers are created for each request. This means you can attach variables to self if you want them passed around. However, it can be very inconvenient to keep track of all the variables and methods attached to self, especially if you want to pass them to a template.

To make it easier to set up your data for use by the template, the variable c is made available and is also available in all Mako templates as the c global. Let's take a look at using it:

1
2
3
4
5
6
def serverinfo(self):
    import cgi
    import pprint
    c.pretty_environ = cgi.escape(pprint.pformat(request.environ))
    c.name = 'The Black Knight'
    return render('/serverinfo.mako')

and modify the serverinfo.mako file in the templates directory to look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<h2>
Server info for ${request.host}
</h2>

<p>
The URL you called: ${h.url_for()}
</p>

<p>
The name you set: ${c.name}
</p>

<p>The WSGI environ:<br />
<pre>${c.pretty_environ}</pre>
</p>

Note

The c object is available in the other template languages.

The pprint.pformat function creates a pretty representation of the object passed to it, and the cgi.escape function html escapes a string. You should now see 'The name you set: The Black Knight' printed out on the page, as well as the WSGI environ dictionary.

If you ask for an attribute on c that does not exist, rather than throwing an AttributeError, an empty string will be returned. This makes it easy to toggle behavior depending on the response. For example:

1
<p>Hi there ${c.name or c.full_name or "Joe Smith"}

Warning

Be careful when setting c attributes that begin with an _ character. c and other global variables are really a StackedObjectProxies, which reserve the attribute names _current_obj, _push_object and _pop_object for their internal methods.

The c global is also reset on each request so that you don't need to worry about a controller still having old values set from a previous request.

8.3   Application Globals and Persistent Objects

There are occasions where you might want information to be available to all controllers and not reset on each request. For example you might want to initiate a TCP connection that is made when the application is loaded. You can do this through the g variable.

The g variable is an instance of your Globals class in your application's lib/app_globals.py file. Any attributes set in the __init__() method will be available as attributes of g throughout your Pylons application. Any attributes set on g during one request will remain changed for all the other requests. You have to be very careful when setting global variables in requests.

Here is an example of using the g variable. First modify your lib/app_globals.py Globals class so that the __init__.py method looks like this:

1
2
def __init__(self):
    self.message = 'Hello'

Then add this new method to the end of the helloworld/controllers/hello.py:

1
2
3
4
5
6
7
def app_globals_test(self):
    if g.message == 'Hello':
        content = g.message
        g.message = 'Hello World!'
        return content
    else:
        return g.message

This time if you run the server and visit http://127.0.0.1:5000/hello/app_globals_test/ you should see the message Hello. If you visit the page again the message will be changed to Hello World! and it will remain changed for all subsequent requests because the application global variable was modified on the first request.

Note

The Globals object is initialized when the application is loaded; the c, cache and other request-scoped variables are not initialized/available at that point.

Warning

Keep in mind that the Globals object can be utilized by all threads in your application. Thread-safety should be considered when using it, especially when modifying attributes of the object.

If you're looking for where to put that should be run before your application is, this is the place.

The syntax seems odd. How about "where to put CODE that should be run"...

James

Posted by James R. Phillips at Sep 30, 2007 20:16 | Permalink

If you're trying to figure out why none of the paste commands work on Windows - it's because you have to run with admin privileges.

Posted by Lance Good at Oct 28, 2007 01:21 | Permalink

I suspect that these are instructions assume that the user is installing on his/her local system. I am trying to install on my VPS host, and I am having some difficulties.

Posted by walter byrd at Jan 22, 2008 17:19 | Permalink

I think the filenames are given with inconsistent working directories. Sometimes they include 'helloworld' and sometimes they omit it. I think you should use a consistent base directory. Thus, in section 8.3, 'lib/app_globals.py' would be 'helloworld/lib/app_globals.py'. The same comment applies to any other file not prefixed with 'helloworld/'.

Posted by Howard B. Golden at Apr 30, 2008 19:53 | Permalink

If you are using this tutorial and get the <type 'exceptions.AttributeError'>: 'module' object has no attribute 'url_for' exception, try editing your serverinfo.mako file, replacing the line: 

1
The URL you called: ${h.url_for()}

with:

1
The URL you called: ${h.rails.url_for()}

Posted by Tony Lambley at Aug 08, 2008 18:56 | Permalink

Thanks for this comment!
While this worked, I got a DeprecationWarning using this method. My solution was to insert these two lines in hello.py under the "from helloworld.lib.base import *" line.

from routes import url_for
h.url_for = url_for

This seems to work OK.

I couldn't import routes in hello.py and then call routes.url_for() in the mako file, as it seems that routes becomes undefined there. I tried "from routes import url_for" and just called the function, but that also caused the same error. Attaching the function to the "h" module was the only way I could get it to work.

Posted by Joseph Rawson at Dec 28, 2008 10:30 | Permalink

UPDATE:

It's probably easier to just add this statement to lib/helpers.py

from routes import url_for

Posted by Joseph Rawson at Dec 28, 2008 10:35 | Permalink

I seem to be stuck at step 5. I've created the hello.py controller, and modified routing.py, but I'm getting:

ImportError: No module named template

ISTM that this indicates two problems. Firstly, pylons hasn't created a template controller as the tutorial indicated that it would. Secondly, routes isn't matching the URLs for the hello controller, and so is trying to trigger the missing template controller.

I'm at a bit of a loss now. Am I missing something obvious?

Posted by Simon Brunning at Oct 01, 2008 09:05 | Permalink

You're probably using the latest Pylons 0.9.7rc2, which does not have the template controller anymore. You'll want to read the docs over at: http://docs.pylonshq.com/ which are updated for 0.9.7.

Posted by Ben Bangert at Oct 01, 2008 21:04 | Permalink
Site running on a free Atlassian Confluence Open Source Project License granted to Pylons. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.3.3 Build:#645 Feb 13, 2007) - Bug/feature request - Contact Administrators
Top