A MVC-ish Umbraco macro with Python

Following up my last post doing the same with IronRuby, here’s a Python-way of achieving a controller-views separation for an Umbraco macro.

DLR goodness : a nice ability to handle basic user actions with a really simple “page lifecycle”

Have a look at the 25 seconds screencast:

The macro Controller has the following Python script attached:

## I'd rather see the macro engine do this, but...
import sys; import clr; clr.AddReference('System.Web'); from System.Web.HttpContext import Current; sys.path.append(Current.Server.MapPath('~/python'))

if Current.Request.RequestType=="GET":
    import view_get
    import view_post

The view_get script is simply this:

print """
<form action="?" method="post">
 <input type="submit" />

and finally the view_post looks like:

print """

Thank you for posting!



  • Nice separation of concerns
  • Possible to add Ajax-functionality
  • Run tests against the individual scripts

Sending an object to the view

A view is not very useful without some dynamic data to display. Let’s say we’d like to add the name of the current page. In that case we’d change our view_get.py to this:

def content(node):
  return """
  <form method='post' action='?'>
    <input type='submit'/>

And the controller.py should be:

import sys; import clr; clr.AddReference('System.Web'); from System.Web.HttpContext import Current; sys.path.append(Current.Server.MapPath('~/python'))
import view_get

if Current.Request.RequestType=="GET":
  print view_get.content(currentPage)
  import view_post

Couldn’t we use currentPage directly from view_get.py? No. The currentPage object is given to us in controller.py at it is the one that is run from the macro (which has the actual Umbraco context, on a page). Also, it suits my example nice. currentPage can ofcourse be replaced by any object, a certain node, a set of properties, a business object or whatever.

Handling the post

import sys; import clr; clr.AddReference('System.Web'); from System.Web.HttpContext import Current; sys.path.append(Current.Server.MapPath('~/python'))
import view_get
import view_post

if Current.Request.RequestType=="GET":
  print view_get.content(currentPage)
  ## Handle the post ... and then print the view with the result data:
  result = "Ok"
  print view_post.content(result)


def content(result):
 return """

 <p>Thank you for posting!</p>
 <p>Result : {result}</p>


Generic form handling

I’m currently working with a class for generic form handling in Python. Progress goes fine. Currently I stumble on a issue with the macro engine. But I hope I can get around that and release a package soon enough. Here’s what my view looks like using the form handler:

import sys; import clr; clr.AddReference('System.Web'); from System.Web.HttpContext import Current; sys.path.append(Current.Server.MapPath('~/python')); from umbraco import library
from rndrForms import *

def content(macroId, macroAlias, pageId):

# I use a form  helper class that automatically renders with ajax-submit
# or fallback  traditional non-ajax submit if no js is running on the client

newForm = rndrForm(macroId,macroAlias,pageId)

# form elements can be added with html:

newForm.addHtml("<input type='text' id='firstname'  name='firstname'/>")

# or with helper functions :

newForm.makeLabelFor("Name","name") # Parameters: Label Text and "label-for"
newForm.makeInputText("name","") # Id and CssClass

# or combining both label & textbox within a div

newForm.makeLabelInputWithDivs("Name", "name", "") # Label text, id of input and CssClass
newForm.makeLabelInputWithDivs("Address", "address", "")


# makeForm renders the form into text, the parameter  tells it to add the javascripts

return newForm.makeForm(True)


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s