How To Guides

These “How To” guides will steer you in the right direction for common aspects of modern web applications and website design.

How Do I: Use a Templating Engine

circuits.web tries to stay out of your way as much as possible and doesn’t impose any restrictions on what external libraries and tools you can use throughout your web application or website. As such you can use any template language/engine you wish.

Example: Using Mako

This basic example of using the Mako Templating Language. First a TemplateLookup instance is created. Finally a function called render(name, **d) is created that is used by Request Handlers to render a given template and apply data to it.

Here is the basic example:

 1#!/usr/bin/env python
 2
 3import os
 4
 5
 6import mako
 7from mako.lookup import TemplateLookup
 8
 9
10from circuits.web import Server, Controller
11
12
13templates = TemplateLookup(
14    directories=[os.path.join(os.path.dirname(__file__), "tpl")],
15    module_directory="/tmp",
16    output_encoding="utf-8"
17)
18
19
20def render(name, **d): #**
21    try:
22        return templates.get_template(name).render(**d) #**
23    except:
24        return mako.exceptions.html_error_template().render()
25
26
27class Root(Controller):
28
29    def index(self):
30        return render("index.html")
31
32    def submit(self, firstName, lastName):
33        msg = "Thank you %s %s" % (firstName, lastName)
34        return render("index.html", message=msg)
35
36
37(Server(8000) + Root()).run()

Other Examples

Other Templating engines will be quite similar to integrate.

How Do I: Integrate with a Database

Warning

Using databases in an asynchronous framework is problematic because most database implementations don’t support asynchronous I/O operations.

Generally the solution is to use threading to hand off database operations to a separate thread.

Here are some ways to help integrate databases into your application:

  1. Ensure your queries are optimized and do not block for extensive periods of time.

  2. Use a library like SQLAlchemy that supports multi-threaded database operations to help prevent your circuits.web web application from blocking.

  3. Optionally take advantage of the Worker component to fire task events wrapping database calls in a thread or process pool. You can then use the call() and wait() synchronization primitives to help with the control flow of your requests and responses.

Another way you can help improve performance is by load balancing across multiple backends of your web application. Using things like haproxy or nginx for load balancing can really help.

How Do I: Use WebSockets

Since the WebSocketDispatcher id a circuits.web “dispatcher” it’s quite easy to integrate into your web application. Here’s a simple trivial example:

 1#!/usr/bin/env python
 2
 3from circuits.net.events import write
 4from circuits import Component, Debugger
 5from circuits.web.dispatchers import WebSocketsDispatcher
 6from circuits.web import Controller, Logger, Server, Static
 7
 8
 9class Echo(Component):
10
11    channel = "wsserver"
12
13    def read(self, sock, data):
14        self.fireEvent(write(sock, "Received: " + data))
15
16
17class Root(Controller):
18
19    def index(self):
20        return "Hello World!"
21
22
23app = Server(("0.0.0.0", 8000))
24Debugger().register(app)
25Static().register(app)
26Echo().register(app)
27Root().register(app)
28Logger().register(app)
29WebSocketsDispatcher("/websocket").register(app)
30app.run()

See the circuits.web examples.

How do I: Build a Simple Form

circuits.web parses all POST data as a request comes through and creates a dictionary of kwargs (Keyword Arguments) that are passed to Request Handlers.

Here is a simple example of handling form data:

 1#!/usr/bin/env python
 2
 3from circuits.web import Server, Controller
 4
 5
 6class Root(Controller):
 7
 8    html = """\
 9<html>
10 <head>
11  <title>Basic Form Handling</title>
12 </head>
13 <body>
14  <h1>Basic Form Handling</h1>
15  <p>
16   Example of using
17   <a href="http://code.google.com/p/circuits/">circuits</a> and it's
18   <b>Web Components</b> to build a simple web application that handles
19   some basic form data.
20  </p>
21  <form action="submit" method="POST">
22   <table border="0" rules="none">
23    <tr>
24     <td>First Name:</td>
25     <td><input type="text" name="firstName"></td>
26    </tr>
27    <tr>
28     <td>Last Name:</td>
29     <td><input type="text" name="lastName"></td>
30    </tr>
31     <tr>
32      <td colspan=2" align="center">
33       <input type="submit" value="Submit">
34     </td>
35     </tr>
36   </table>
37  </form>
38 </body>
39</html>"""
40
41
42    def index(self):
43        return self.html
44
45    def submit(self, firstName, lastName):
46        return "Hello %s %s" % (firstName, lastName)
47
48
49(Server(8000) + Root()).run(

How Do I: Upload a File

You can easily handle File Uploads as well using the same techniques as above. Basically the “name” you give your <input> tag of type=”file” will get passed as the Keyword Argument to your Request Handler. It has the following two attributes:

.filename - The name of the uploaded file.
.value - The contents of the uploaded file.

Here’s the code!

 1#!/usr/bin/env python
 2
 3from circuits.web import Server, Controller
 4
 5
 6UPLOAD_FORM = """
 7<html>
 8 <head>
 9  <title>Upload Form</title>
10 </head>
11 <body>
12  <h1>Upload Form</h1>
13  <form method="POST" action="/" enctype="multipart/form-data">
14   Description: <input type="text" name="desc"><br>
15   <input type="file" name="file">
16   <input type="submit" value="Submit">
17  </form>
18 </body>
19</html>
20"""
21
22UPLOADED_FILE = """
23<html>
24 <head>
25  <title>Uploaded File</title>
26 </head>
27 <body>
28  <h1>Uploaded File</h1>
29  <p>
30   Filename: %s<br>
31   Description: %s
32  </p>
33  <p><b>File Contents:</b></p>
34  <pre>
35  %s
36  </pre>
37 </body>
38</html>
39"""
40
41
42class Root(Controller):
43
44    def index(self, file=None, desc=""):
45        if file is None:
46            return UPLOAD_FORM
47        else:
48            filename = file.filename
49            return UPLOADED_FILE % (file.filename, desc, file.value)
50
51
52(Server(8000) + Root()).run()

circuits.web automatically handles form and file uploads and gives you access to the uploaded file via arguments to the request handler after they’ve been processed by the dispatcher.

How Do I: Integrate with WSGI Applications

Integrating with other WSGI Applications is quite easy to do. Simply add in an instance of the Gateway component into your circuits.web application.

Example:

 1#!/usr/bin/env python
 2
 3from circuits.web.wsgi import Gateway
 4from circuits.web import Controller, Server
 5
 6
 7def foo(environ, start_response):
 8    start_response("200 OK", [("Content-Type", "text/plain")])
 9    return ["Foo!"]
10
11
12class Root(Controller):
13    """App Rot"""
14
15    def index(self):
16        return "Hello World!"
17
18
19app = Server(("0.0.0.0", 10000))
20Root().register(app)
21Gateway({"/foo": foo}).register(app)
22app.run()

The apps argument of the Gateway component takes a key/value pair of path -> callable (a Python dictionary) that maps each URI to a given WSGI callable.

How Do I: Deploy with Apache and mod_wsgi

Here’s how to deploy your new Circuits powered Web Application on Apache using mod_wsgi.

Let’s say you have a Web Hosting account with some provider.

Configuring Apache

The first step is to add in the following .htaccess file to tell Apache hat we want any and all requests to http://example.com/~joeblogs/ to be served up by our circuits.web application.

Created the .htaccess file in your Docroot:

ReWriteEngine On
ReWriteCond %{REQUEST_FILENAME} !-f
ReWriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /~joeblogs/index.wsgi/$1 [QSA,PT,L]

Running your Application with Apache/mod_wsgi

The get your Web Application working and deployed on Apache using mod_wsgi, you need to make a few changes to your code. Based on our Basic Hello World example earlier, we modify it to the following:

 1#!/usr/bin/env python
 2
 3from circuits.web import Controller
 4from circuits.web.wsgi import Application
 5
 6
 7class Root(Controller):
 8
 9    def index(self):
10        return "Hello World!"
11
12
13application = Application() + Root()

That’s it! To run this, save it as index.wsgi and place it in your Web Root (public-html or www directory) as per the above guidelines and point your favorite Web Browser to: http://example.com/~joeblogs/

Note

It is recommended that you actually use a reverse proxy setup for deploying circuits.web web application so that you don’t loose the advantages and functionality of using an event-driven component architecture in your web apps.

In production you should use a load balance and reverse proxy combination for best performance.