Using IronPython in Umbraco – pyForum part 1

This is the first in a series of blog posts about IronPython in Umbraco.

I find IronPython (I’ll just write Python further on) to be a great middle way between Xslt and C# in Umbraco. It combines the ease of creating dynamic html right in the Umbraco UI with the power of a modern oo programming language that has access to .net and umbraco dll’s.

To have something fun to deal with in this posts we’re going to create a basic forum. Without a singe line of Xlst, C# or VB.Net. Only Python.

Disclaimers : I’m no expert in Python. Far from it – I just started some week ago. This is written as I learn and experiment myself. Also, English is not my first language, and I sometimes stumble using it. So some grammar and spelling errors will wait ahead. Comments and improvement suggestions are most welcome.

In the third post in this series you find a link to a demo and a complete pyForum package of the version up to the point of part 3. (New version on the demo running here.)

Umbraco building blocks for our pyForum

The forum need a simple structure within Umbraco to be able to store and show some forum content. The document structure with some threads and posts will look like this:

Site home
--Forum start
----First thread
------Answer 1 (post)
------Answer 2 (post)
------Answer 3 (post)
----Second thread
------Answer 1 (post)
----Third thread

Document types

We store data in the Umbraco document structure with the help of three very simple document types.

pyForumStart is the container for our forum. Under it we store threads (pyForumThread) and on the third level we have posts (pyForumPost). I choose to separate thread and post data types, mostly because I like them to appear differently in Umbraco UI.

pyForumStart
--pyForumThread
----pyForumPost

pyForumStart is just a empty document type that we use for the forum name, allowing document type pyForumThread as child.

pyForumThread and pyForumPost have two properties to begin with, richtext (rich text editor data type) which contains the actual post text and username (text). pyForumThread allow pyForumPost as a child document type. (For simplicity I dont use hierarchy data types here.)

Document templates

We make use of three document templates from the start. pyForumMaster which is the topmost master template, then we have pyForumStart and pyForumThread.

pyForumMaster
--pyForumStart
----pyForumThread

pyForumStart just has basic html-structure plus a content place holder for our child master pages. In our pyForumStart template we have a macro that lists titles of all existing threads with links. And in pyForumThread a macro that shows thread and posts under it.

Enter Python

Now to our Python code. You can find info of the basic syntax in zillion places on the net. I will try to explain just something of the special things with python – assuming you have knowledge of other languages (c#, javascript, vb.net …).

In Umbraco we find our Python files in the Developer section under Scripting Files. To make them useful in templates we use regular Umbraco macros, just as when we write Xslts.

The Hello World sample would look like this in Python:

print "Hello World!"

Some very brief information about Python syntax

Like I said before you find information about Pyhon on many places. The official place to go is www.python.org , for a compressed list with the most important information I really like codesyntax.netfirms.com/lang-python.htm (great one!). Here’s a minimal list of what you need to know about the language.

Variables are strongly typed but you don’t declare them.

Huh? Yeah, they simply get their type from the first value they get. It’s called duck typing. “If it walks and talks like a duck…” yada yada, google on that.

stringvariable = "Name"
numericvariable = 3333

Python don’t need semicolons at the end of each line (but they are allowed).
Code blocks are made just with indentation. So no need of brackets. Also don’t use parenthesis to enclose if-expressions:

x = 2
y = 3
if x > y:
    print "x is greater than y"
elif x==y:
    print "equal they are"
else:
    print "y is greater than x"

A basic for-loop:

for c in currentPage.Children:
    print c.Name

The statement print sends a string to the output stream, in Umbraco that is our rendered macro.

A function looks like this:

def NodeName(node):
    return node.Name

And a function call looks like this:

currentPageNodeName = NodeName(currentPage)

A recommendation for a Python script structure for use in Umbraco

The simplest Python file can consist of just a few lines of code and thats it. But when we build something a little more complex it is very good to lean on some kind of structure. After some struggling I have found myself comfortable ordering things this way :

  1. Imports – for external dll’s and python files
  2. Template htmls – string variables containing html with place holders for dynamic content
  3. Helper functions
  4. Main function
  5. And finally just a statement that prints out the result of the main function

Start coding our pyForum

Using the mentioned file structure, we can start looking at the code for our forum. First we write the code for our pyForumStart-macro, which will only print a header and a list of the threads with links. Like this:

Py Forum Demo – part 1

Template htmls (part 2 of our Python script)

The templates are simply string variables containing html code and place holders:

forumStartTemplate = """
 <div>
   <h1>{forumname}</h1>
 </div>
 <ul>
   {forumThreads}
 </ul>

 """

forumThreadTemplate = "<li><a href='{threadlink}'>{subject}</a></li>"

The triple quote is the Python way of handling multi-line strings. {variable}s is the place holders for content. In our main function we will use the built in python string method .format() to replace our place holders with content.

Main (part 4 and 5 of our Python script)

Here’s the main part of our pyForumStart macro script:

def ForumStartView():
   def ForumThreadsHtml():
       retval = ""
       for c in currentPage.Children:
           threadlink = library.NiceUrl(c.Id)
           subject = c.Name
           retval += forumThreadTemplate.format(subject=subject,threadlink = threadlink )
       return retval

   forumName = currentPage.Name

   return forumStartTemplate.format(forumname=forumName, forumThreads=ForumThreadsHtml())

print ForumStartView()

I hope it’s pretty self explanatory. There’s a function constructing the main html string for our forum start view. Enclosed in that function we have another function building the list of threads html. Also note the .format() – method mentioned earlier.

currentPage

Note the currentPage object, which Umbraco gracefully gives us to play with. It’s a umbraco.presentation.nodeFactory.Node of the current page. We can use that object just as if we were in C#, for example:

print currentPage.Name
print str(currentPage.Id)
print currentPage.GetProperty("propertyname").Value
for c in currentPage.Children:
    print c.Name
if currentPage.Parent:
    print currentPage.Parent.Name

Imports and helper functions (part 1 and 3 of our Python script)

We need to include a import to be able to use the umbraco.library – which we use to get nice url strings for our threads:

from umbraco import library

Umbraco being the namespace and library the class we import.

We don’t use any helper function just yet.

The complete code for this blog post

#
# Imports
#

from umbraco import library

#
# Html Templates
#

forumStartTemplate = """
 <div>
   <h1>{forumname}</h1>
 </div>
 <ul>
   {forumThreads}
 </ul>

 """

forumThreadTemplate = "<li><a href='{threadlink}'>{subject}</a></li>"</pre>

#
# Main function and call
#

def ForumStartView():

   def ForumThreadsHtml():
       retval = ""
       for c in currentPage.Children:
           threadlink = library.NiceUrl(c.Id)
           subject = c.Name
           retval += forumThreadTemplate.format(subject=subject,threadlink = threadlink )
       return retval

   forumName = currentPage.Name

   return forumStartTemplate.format(forumname=forumName, forumThreads=ForumThreadsHtml())

print ForumStartView()

Thats it for today

That’s it for the first post. In the next post we’ll add a form and code to handle the post backs. Part 2.

Advertisements

2 thoughts on “Using IronPython in Umbraco – pyForum part 1

  1. NICE!

    I’ve always wanted to play with IronPython in umbraco but never had the chance. Thanks for a great article. You’re making this very easy to understand.

    Looking forward to the rest of the series!

    cheers,
    doug.

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