Be Safe with Django 1.2


Transitioning to using Django 1.2 templates with AppEngine has been a real adventure, and this is just the second in a series of posts about my experience with it. I am glad to have the increased power that is in the newest version of the template language, but I have paid a steep price in hours spent making changes to be compatible with it.

For a good chunk of last night and spots of time here-and-there today, I have been going through my code and adding the |safe filter to variables that might contain HTML that needs to be rendered. Django 1.2 assumes that you want your variables to be escaped. While that is a good practice to prevent spammers and script kiddies from abusing your site, I always assume that I need to sanitize on input rather than output, and I consider all of my stored data to be safely renderable.

There are a couple of ways to prevent Django from escaping your variables. I have chosen to append the |safe filter. Why? Well, it is safer. As I said, I sanitize on input, but there’s always a chance that I will have overlooked something, and some persistent fool will figure out a way to game me. As long as I have to manually look at my templates, models and controller code before I decide that something is safe, I feel confident that my application is going to be OK.

If you are less risk averse -- or maybe just lazier -- than I am, you can get the same effect by simply placing an {% autoescape off %} {% endautoescape %} at the outermost level in your template hierarchy. To me, that is tempting fate and failure, but you are the best judge of own your own liabilities.

Most importantly, don’t get caught with a busted app after you innocently follow the directions on how to set a specific version of Django in you AppEngine application. This blog spent several days with a non-functioning Atom feed because I never really thought to check it after the upgrade.

Who really thinks about their feed once it’s working?



Fixing Custom Tags with Django 1.2

When I upgraded to version 1.4.2 of the AppEngine SDK, I was both intrigued and alarmed to see the warning message that I ought to be using use_library() to specify a version of Django that my application would use. On one hand, I was glad that I could switch to version 1.2, as it provides dramatically-improved if tags over 0.96. On the other hand, I knew that I would be in for a certain amount of pain because things were going to break. The first thing that broke for me was the call to template.register_template_library that my code uses to load a library of custom template tags. It crashed with the extraordinary helpful stack trace:

File "C:\google_appengine\google\appengine\ext\webapp\template.py", line 269, in register_template_library
File "C:\google_appengine\lib\django_1_2\django\template\__init__.py", line 1049, in add_to_builtins
File "C:\google_appengine\lib\django_1_2\django\template\__init__.py", line 984, in import_library
   app_path, taglib = taglib_module.rsplit('.',1)
ValueError: need more than 1 value to unpack 

After a great deal of stepping through code in Wing IDEs superb Debugger, I figured out that the register_template_library call had changed. Instead of taking an absolute path to the file to load, it expects a Python Module style path like we use with an import statement.

The fix was simple. I created a directory called ‘tags’ and moved my custom tags library file (MVCTags.py) there. I also added an empty __init__.py file to make it a Module. Finally, I changed the code to template.register_template_library(‘tags.MVCTags’).

With that out of the way, I have moved to fixing the next big problem: a change to the way that template loaders work has broken many of the include statements in my templates. It looks like I am going to be writing a custom template loader, but figuring out how to get it into the collection of template loaders looks daunting.


Still learning, still liking

I'm continuing to work on this blog software, and I am learning a lot about AppEngine, Python and Django.  I used Django's include function to refactor the rendering of posts.  That removed some code duplication.  Got to love that.  I feel like I've already done a full day's work, and it's only 10:30!

My inclination is next to look at extending Python's WSGIHandler further to make it more MVC-like.  I'd never paid much attention to that design pattern before I started using Ruby on Rails, but I'm quite addicted to it now, and doing the extra work -- and admittedly, it's not that much -- to do it the AppEngine way irks me.  I've already taken a step in that direction, subclassing RequestHandler to do all the work of creating a path to the appropriate template file and passing it to the render method, but I know that there's a lot more to do.  I also feel like I could refactor the handling of the dictionary that passes values to the template to reduce the repititious setting of values that happens in each handler.


Live at Last!

Learning to create Google App Engine applications via building this simple blog has been hugely fun and not just a little bit frustrating.  Many, many thanks to Google's Marzia for so diligently helping me to figure out the missing piece that kept me from being able to upload this code.

I've come away from the experience feeling very enthusiastic about App Engine.  It's not going to replace Ruby on Rails as my web development platform of choice, but I have to admit that GAE makes it very, very easy to quickly build and deploy an application.  I managed to become a pretty competant Python programmer in just a few days, and I know enough about Django to build a small web application that observes the DRY principle.

I became very frustrated that Django is a whole seperate language unto itself, so I had to learn Python and Django.  I suppose that I have become spolied by Rails, which allows me to write the logic, data and presentation layers in one language.  It's so simple, beautiful and elegant.

That's not neccesarily an argument against GAE, which it seems is going to support multiple language and frameworks as it matures.  The combination of Ruby on Rails's power with Google's essentially infinite scalability would be a mighty and compelling thing.


Fixing the TemplateDoesNotExist error AppEngine/Django 1.2

When I converted my blogging application from Django 0.96 templates to 1.2, I encountered three problems that set me back a few days: my custom template tag libraries stopped working, all of the output had its HTML content escaped and all of my templates that used extends or include broke. I described how I resolved the first two issues in my most recent two posts, and I have been planning to cover the third issue, but I procrastinated.

Yesterday, a fellow AppEngine programmer posted a question on StackOverflow about the exact problem that I had fixed, so I bit the bullet and wrote up a lengthy answer describing my solution. I hope that someday soon I might have the time required to cover the subject matter more comprehensively, but for the time being, here is the question with my answer on StackOverflow.

You'll know that you care about this if your AppEngine application has suddenly started throwing TemplateDoesNotExist exceptions.