msgbartop
by Brian Neal
msgbarbottom

14 Feb 09 Member Map Part 2

I’ve gotten the Member Map application ported to my Django powered site now. This was pretty straightforward and a lot of fun because of the Javascript aspect. Let me address the points I made in part 1 of this post, below.

  1. Leveraging jQuery. I did make use of jQuery for the client side Javascript. This really did simplify things. In the old version of the code, I had a 282 line Javascript file. The new version weighs in at 161 lines, which is 57% the size of the earlier version.
  2. Use of JSON encoder library. It turns out that Django includes a version of the simplejson library already. This is used in Django’s serialization feature. I probably could have used this feature, but I didn’t need to serialize an entire model, and wanted to rename some of the fields. So I simply did a “import django.utils.simplejson as json” and went to town. My server side code was now much simpler than the previous version where I encoded by hand.
  3. I did continue to use the markItUp! editor to let users edit their message to go along with their location. I learned that the size of the editor is easily adjusted through the use of CSS. So I was able to override the default size of the editor by including my own CSS style sheet below the default sheet.
  4. Reducing complexity. Here is where it got interesting. I decided to add a “json” field to the MapEntry model. This field is populated whenever a model object is saved by providing my own save() method. Inside my save() I use Django’s template render_to_string() to render the HTML  message that appears in the pop-up balloon on the map. This consists  of the user’s avatar followed by a message that is marked up in Markdown. I then build a JSON representation of the MapEntry using Django’s simplejson. This representation consists of the following fields: name, location, latitude, longitude, and the HTML message. By pre-saving all of this information, it makes it much more efficient to retrieve 200+ users’ information when the map is first loaded. In the view function, I make use of the values_list() queryset method to retrieve all the json fields. I don’t need the ORM to convert each MapEntry to an actual Python object.

Another thing I did differently for the port was when a user updates or adds their position on the map, I don’t reload the entire map. I just adjust their information to reduce bandwidth with an AJAX post. I’m not sure why I didn’t do this before, perhaps because it was to tedious to do without jQuery. It was just easier to reload the whole thing.

This was all well and cool, doing all this pre-computation, but what happens when a user changes her avatar? Her entry on the map will likely have a broken graphic. No problem. Here I took advantage of Django’s signals. I attached a signal handler to listen for changes to the UserProfile model. Whenever the UserProfile is saved, my signal handler runs and re-saves the corresponding MapEntry to regenerate the JSON. Very slick.

And finally, another thing that I learned about Django was that simple_tags can have defaulted arguments. I added an argument to my avatar tag so that I could apply CSS to the generated HTML img tag if needed. In the Member Map pop-up balloon, it looked nicer if the avatar was floated to the left.

So all and all, again, I’m very happy with how easy Django makes writing an application like this. Using jQuery was also a big productivity booster.

Here are some screenshots. You can also see the new Blueprints CSS in action as well.

Member Map

Member Map 1

Member Map

Member Map 2

Tags: , , , ,

06 Feb 09 Member Map Part 1

I started working on the Member Map application last weekend. This will be a port of the PHP-Nuke module I wrote, which you can find here. In a nutshell, this application displays a Google Map on your site, and allows site members to place markers representing their location on the map. If you click on a marker, a balloon pops up which displays the user’s avatar, a link to their profile, and a short message that they have typed previously. The Nuke version of this application is a big hit on the current site, and last time I checked, we had over 220 members on the map.

The existing application consists of the PHP-Nuke code, written in PHP, on the server side, and a fair amount of Javascript on the client side. All interaction with Google Maps is done through the Javascript code.

For the port to Django, I want to do a couple of things different.

  1. Leverage jQuery in the client-side Javascript. The existing version was written before I was aware of Javascript libraries, and it is all “vanilla” Javascript. By using jQuery, the amount of code I have to write will be much smaller. And by taking advantage of jQuery, it should be more portable and browser robust.
  2. On the server side, the existing application did not use any JSON encoder library. I simply constructed the JSON by hand. I can’t remember why I did this. I think it was partly because I didn’t know any better, and partly because the PHP version I had on the original hosting server may not have had it. I will explore what Python and/or Django options exist.
  3. I’ll leverage the markItUp! editor that I’ve been using for comments to let the users enter Markdown comments. I’ve used this in the last couple of apps I’ve written and it will be easy to implement. The only concern with doing this is the user may be tempted to write a lot more than in the older app, and it may make for large “balloons”. We’ll see.
  4. I want to make the new application less database and computationally intense than the older version. I don’t have any problems running the current version with 200 users, but I think I could do it a bit smarter this time around. This means I am going to try to save marked up and JSON encoded strings in the database rather than compute them on every page load. I am also wary of instantiating 200+ map entry model objects with the Django ORM (albeit in a loop) just to generate the JSON. Luckily Django lets you use raw SQL when needed. But in this case I think a simple use of the values() method will really be useful here.

So, those are my going in goals. I’ve already started working on this, and I’ve learned a lot so far. In the next post or two I will detail the progress and what problems I ran into.

Tags: , , , ,

14 Jan 09 Update on Comments and CSS Woes

I’ve made good progress on the comments system, and I’m glad I took the time to roll my own. I have a nice AJAX style commenting system integrated with the markItUp! editor. I’m allowing comments to be marked up with Markdown, and I’m very happy with it. Having the ability for users to easily post links and images will be a big improvement from the existing site’s commenting systems.  I need to cut the private messages application over to markItUp instead of TinyMCE. I think TinyMCE is a bit overkill for anything except news stories. I also added the ability for users to “flag” comments for spam or abuse.

The markItUp editor is very nice, and I was even able to add a drop-down menu for my smiley system. Now one can click on a smiley from the editor and get it added to the comment! The markItUp editor has a slick preview system, which can use AJAX to post what the user has typed so far and get an HTML response. The only drawback is I can’t easily clear or hide the preview pane once the comment has been posted by AJAX. So you are left with a blank editor ready for the next comment, but the preview pane is still showing whatever you previewed last. This is minor, I think, and I’ve already made the author aware of this issue. He told me he will look into it for the next release. I highly recommend markItUp.

And finally I took a cue from Malcom Tredinnick’s blog (the Django source is available for study – Thanks Malcom!). I added a field to the comments table to store the rendered HTML for each comment. This field is updated on each comment object’s save. This will save processing time to convert the Markdown markup to HTML. Since comments are viewed many, many times compared to how often they are edited, this seemed like a sensible optimization at the expense of some disk space.

I need to add comments to the other parts of the system I have developed already (news, polls, etc.). However I’m being distracted at the moment by a problem I am having with CSS. This has been bugging me for months now. I don’t know why it happens, but I’m seeing <div> tags in a left floating <div> affect <div> tags in my main content area. Large gaps get created. It seems that I may be trying too hard to duplicate the PHP-Nuke blocks, and nesting lots of divs seems to be very fragile. I think I might have to investigate a different CSS layout and redo my base template. I’m googling various CSS layout tutorials in my spare time. I don’t want to become an expert in this, but I need something simple that looks decent. I wish I had a web designer to help me out with this part.

Tags: , , ,