Deploying circuits.web with Nginx/uwsgi

Explanation

Here we load the Controller module, and wsgi Application module from circuits.web. Essentially the peices we need to not only serve a WSGI application, but to handle the requests being sent to the app.

from circuits.web import Controller
from circuits.web.wsgi import Application

This is the main Root controller.

class Root(Controller):

Here we store some HTML output into formpage for later use

	formpage = """\
	<html>
	 <head><title>Basic Form Handling</title></head>
	 <body>
	  <form action="/submit/" method="POST">
			First Name: <input type="text" name="firstName"><br>
			Last Name: <input type="text" name="lastName"><br>
			<input type="submit" value="Submit">
	  </form>
	 </body>
	</html>"""

When visiting http://myapp.example.com/ , the main index is served with a simple string

	def index(self):
		return "Hello World!\n"

When visiting http://myapp.example.com/query/?foo=bar&more=stuff circuits.web will parse the query string into a dictionary called data and then will print out each key=value received. **data can also capture key-values sent via POST.

Notice how /query/ invokes the query function under the Root controller.

	def query(self, **data):
		q = ["%s=%s" % (k, v) for k, v in data.items()]
		querystring = '<br>'.join(q)
		return "Values passed:<br>%s" % (querystring)

Similar to the query function above, we check to see if a object say has been passed, and if it has the value of yes.
http://myapp.example.com/sayyes/ -> “You didn’t say anything”
http://myapp.example.com/sayyes/?say=no -> “You didn’t say ‘yes'”
http://myapp.example.com/sayyes/?say=yes -> “You said yes…”

	def sayyes(self, **data):
		if not "say" in data:
			return "You didn't say anything"
 
		if not "yes" in data["say"]:
			return "You didn't say 'yes'"
 
		return "You said yes..."

Remember the stored HTML string above, here when someone visits /form/ that data will be returned to the browser.

	def form(self):
		return self.formpage

The form above submits POST data to /submit/ , as a result the values will be shown to the browser.
Notice how the arguments can be defined in the function like above, but predefined to the field name.

	def submit(self, firstName, lastName):
		return "Hello %s %s<br /><a href=\"/form/\">Return</a>" % (firstName, lastName)

And now we have a new controller. Notice how there is a channel=”/math”, this controller will only be invoked if http://myapp.example.com/math/* is requested. In this way you can create a number of controllers bound to a specific URI.

class SomeMath(Controller):
	channel = "/math"

Here we have a very simple arithmetic function, adding two numbers passed to it:
http://myapp.example.com/math/addtwo/ -> “You need two numbers, missing both”
http://myapp.example.com/math/addtwo/2/ -> “You need two numbers, missing second”
http://myapp.example.com/math/addtwo/2/3/ -> “2 + 3 = 5”
Note: Other than checking for the existence of arguments, it does not validate the inputs

	def addtwo(self, firstNum, secondNum):
		if not firstNum:
			return "You need two numbers, missing both"
 
		if not secondNum:
			return "You need two numbers, missing second"
 
		newNum = int(firstNum) + int(secondNum)
 
		return "%d + %d = %d" % (int(firstNum), int(secondNum), newNum)

Similar function to above, however will process any number of arguments. But we also validate the input here, and catch the error if one occurs.
http://myapp.example.com/math/addmulti/1/2/3/4/ -> “The sum of the numbers you provided was 10”
http://myapp.example.com/math/addmulti/1/oops/4 -> “One or more numbers was not valid”

	def addmulti(self, *args):
		try:
			total = sum([int(x) for x in args])
		except ValueError:
			return "One or more numbers was not valid"
 
		return "The sum of the numbers you provided was %d" % (total)

And here we tie it all up, notice how we just add on each controller as we need it.

application = Application() + Root() + SomeMath()

Comments are closed.