Wednesday, October 28, 2009

Structure and Interpretation, LISP and Python

I'm a "city boy" when it comes to programming languages. 90% of my experience in programming is in ridiculously high level languages like VB.NET, C#, and Python. I haven't "roughed it out" much in the wilderness of some low level language.


I had heard talk about MIT's Open Courseware, but wasn't sure what the hoopla was all about. Based on a reference in someone's blog post, I happened upon a 1986 recording of Structure and Interpretation of Computer Programs (YouTube). I watched the whole thing. I am thoroughly blown away.

I'll admit, the first 20 minutes were dizzyingly abstract, but once some code samples started to show up, it began to make sense. What I was floored the most about was seeing how much an influence LISP had over the language I've been working in the most lately -- Python. All of the "funky things" that I wasn't used too from C#, inner methods, using "def" instead of "function", etc. etc. were all elements of LISP.

So having FizzBuzz on the mind, I decided to give it a shot.... in LISP (and then after recursively in Python). The course professor noted that LISP had no for loops. "A challenge" I thought to myself. (Long Side Tangent: I feel at the moment as if I'm creating a programmer's Fight Club where I mentally abuse the comfortable high-level language life I once knew to get down and dirty fighting with the bare essentials of computational logic. [end sensationalistic, metaphoric movie reference])

In case you're not familiar with FizzBuzz, here's the problem:
Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".
I "made up" a function definition for print since the details of printing to the screen weren't really my concern.


The odd part for me was after working through the mental process of how the solution would work recursively in LISP, writing it again in Python felt ridiculously easy...



Look mom, no loops!

Monday, October 26, 2009

Notating Environment in Django's settings.py

I answered a question (#1626326) on Stack Overflow recently about Django setttings.py files which reminded me I'm still undecided on what the best way to handle this issue.

The issue is -- How do you handle Django settings which change based on which environment the web app is running in? The Django documentation recommends using something to this effect.

if DEBUG:
VALUE = 'something'
else:
VALUE = 'something else'
I used this approach for a while, but found that it was becoming limiting. The reason why is that it doesn't actually address the issue of environment. Where the "if DEBUG" trick is used, we're really only looking to see if we're in DEBUG mode, not if we're running in a development or production environment.

When I was first setting up django-compressor (which by the way is teh hotness) I wanted to sets the setup in a development environment with DEBUG=False. The "if DEBUG" failed miserably here.

settings.py Version 2
So my next attempt was to attempt to determine the machine the settings.py was being evaluated on, and from there set what the environment was.
PRODUCTION_SERVERS = ['WEBSERVER1','WEBSERVER2',]
if os.environ['COMPUTERNAME'] in PRODUCTION_SERVERS:
PRODUCTION = True
else:
PRODUCTION = False

DEBUG = not PRODUCTION
TEMPLATE_DEBUG = DEBUG

# ...

if PRODUCTION:
VALUE = 'something'
else:
VALUE = 'something else'
This is easily an improvement over "if DEBUG". At least now we have some control over values based on environment. I used this for a while and then realized...

What if I have two installations of Django running on the same physical machine but which should be running in different environments?

This is a conceivable situation. Let's say in a smaller company like the one I work in we only have 1 webserver. Departments request features from the web team, which then get implemented by developer(s). However the features need to be tested by the web team and evaluated by the department before deployed to the production site.

So, the webserver gets configured to run 2 virtual hosts: One for "testing.domain.com" and another for "www.domain.com." BAM! The "if PRODUCTION" method just failed. Why? Because we technically now have 3 environments (development, testing, production), 2 of which run on the same physical server.

Imagine this bit of settings.py...
if PRODUCTION:
DATABASE_HOST = '192.168.1.1' # Production MySQL
else:
DATABASE_HOST = 'localhost'
Bad things would follow. The testing copy of the web app (testing.domain.com) would load up, and mark PRODUCTION=True as it is technically on the production server. It then uses the production MySQL database. Fail.

To overcome this, our settings.py file really needs a way to distinguish what environment it is regardless of which physical machine it's located on.

settings.py Version 3
Some ideas I've had to address this would to set the environment based on...
  • The folder path the app is currently located in
    The code for this could get ugly easily.

  • The complete hostname the server is running under
    This might be win.

  • Something else?
I'll post some code when I find something that works well that I like.

On a related note, I was reading the Sinatra (ruby) documentation this week, and I noticed that it automatically sets the environment based on the values set by the RACK_ENV variable. This would be the equivalent of adjusting the settings.py based on the presence of a WSGI or FCGI (or whatever) variable. It seems like a really neat idea, however it's somewhat dependent on the way Django is being loaded, and given that there are so many possibilities, I'm not sure if it'd work out as well for Django as it does for Sinatra.

Friday, October 16, 2009

Neat Django Admin Tricks (Part 1)

About django admin in a sec. First a bit of setup:

As I've been organizing our office into using an issue tracker for keeping track of our Django app, I haven't really found one that 'fit' yet. The issue trackers I looked at had 1 of 2 problems:

  1. They were massive, huge, enterprise-level monsters. I need something for 3-4 people.
  2. They required a bunch of extra setup. I already have a Django app running, why load the server with extra software?
So I spent a few hours after work putting a simple issue tracker together. To really improve the usability and get what I wanted out of the app, I needed to control how the django admin was presenting things. Some neat django admin tricks were in order.

Making An Admin list_display Field Show In Color
By default, all values in the Django admin model list view are in black.

Photobucket

Boring black. If you have an issue tracker it should show in color, right? Here's what my issue admin was looking like:
class IssueAdmin(admin.ModelAdmin):
list_display = ('title', 'priority', 'completed', 'assigned_to', 'last_modified')
The easiest way to get the 'priority' column in color would be to render it as HTML. If you were to try this, you'd find that the Django admin does not escape that value, and you'd end up with < >'s showing. However, there is an API to get around that. In Python all functions are objects. Because of this, we can add a property '.allow_tags' at runtime to signal to Django that the value contains tags.
# models.py
def priority_html(self):
return u'<span >%s</span>' % self.get_priority_display()
priority_html.allow_tags = True
Our value now shows in color, but the column header renders as "Priority html". We can add one more property 'short_description' which would allow us to specify the equivalent of 'verbose_name' for a field.

Here's the (almost) complete code to achieve a custom HTML value in a list_display entry:
# models.py
class Issue(models.Model):

PRIORITY_CHOICES = (
(1, 'Low'),
(2, 'Normal'),
(3, 'High'),
)

priority = models.IntegerField(choices=PRIORITY_CHOICES, help_text='Default: Normal Priority', default=2)

def priority_html(self):
if self.priority == 3:
color = "652D90"
elif self.priority == 2:
color = "37B34A"
else:
color = "26A9E0"
return u'<span style="color:#%s">%s</span>' % (color, self.get_priority_display())
priority_html.allow_tags = True
priority_html.short_description = 'priority'

# admin.py
class IssueAdmin(admin.ModelAdmin):
list_display = ('title', 'priority_html', 'completed', 'assigned_to', 'last_modified')


Photobucket

Given the code above, I bet you can guess how the (Email) link was achieved.

Friday, October 2, 2009

Managing Django Dependencies via SVN

One of the things that's been somewhat of a small hassle in working with Django/Python is managing dependencies across multiple developer machines, especially through an SVN managed project. Whenever a new dependency is needed, we've ended up doing 1 of 2 things:

  • Adding the name of the package to a text file which can be "easy_install "
  • Copying the zip/bz/exe to a folder "dependencies"
In both cases, what normally happens is Developer X will add a dependency to the repo. Developer Y at some point does an SVN update, and pulls down the code Developer X committed. Developer Y runs his runserver and BAM! not found! So then Developer Y has to go and look in the "dependencies" folder and try and figure out if he needs to run an easy_install or run an exe or whatever.

Obviously a rather inefficient task. I had heard about systems that will do automatic dependency installing, but the problem I had with that is that sometimes you have dependencies that are just a single file, and other times a whole package, others are in Pypi, etc.. The packages come in a huge crazy mess of ways. I wanted something consistent.

My (somewhat hacky) Soultion
Create a 'dependencies' folder that lives inside the project root (mine is named "_dependencies"). This folder will hold everything needed by Django (except Django itself) that would normally go in 'site-packages'.

When the Django app starts, have this path added to the Python path, so that libraries can be installed to it, instead of ..\Python26\Lib\site-packages. This allows dependencies to be setup in a folder that everyone pulls down via SVN. Bingo!

There are mainly 2 times when we need to make sure that dependency path is available:
  1. When we're doing a management task (including runserver)
  2. When the production site actually handles a task via Apache or whatever
To accomplish both, I came up with the following code:

# manage.py (before Django loads itself)

import os
import sys

def set_dependency_path():
dep_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), '_dependencies')
if not dep_root in sys.path:
sys.path.append(dep_root)

set_dependency_path()


# __init__.py (the main, root init)

from manage import set_dependency_path
set_dependency_path()

Thursday, October 1, 2009

Hacking wmd-editor into using a custom image gallery

Oh man, I feel accomplished. I just finished hacking wmd editor to use a custom image gallery being generated server-side.

If you don't know, WMD editor is a WYSIWYG editor written in Javascript.
Photobucket

By default, when you click on the 'Insert Image' button you get a prompt allowing you to enter a URL.

Insert Image Screen
Photobucket

The functionality I was looking for was instead of showing you a text box where you could paste in the URL, I wanted to see more of a gallery type interface, that showed media that both you and others had uploaded. I also wanted to have a system where multiple files could be uploaded at once, and multiple files could be inserted at once.

There were primarily two challenges in attempting to accomplish that plan:

  • The WMD editor code doesn't really come with documentation. There are a handful of in-line comments and that's all you get. For the most part, I ignored them and read the code instead.
  • The WMD editor code is a little strange in areas.
Modifying WMD Editor
For the most part, I ended up not needing to change really all that much code. WMD editor is odd, yes, but workable.

The first task was to replace the default prompt function, with my own....
command.doLinkOrImage = function(chunk, postProcessing, isImage){

// ...

if (isImage) {
// OLD: util.prompt(imageDialogText, imageDefaultText, makeLinkMarkdown);
// WMD_IMAGE_GALLERY_URL loaded from a global settings elsewhere
util.imageGallery(WMD_IMAGE_GALLERY_URL, makeLinkMarkdown);
}
else {
util.prompt(linkDialogText, linkDefaultText, makeLinkMarkdown);
}
}

This was an easy change, and allowed to to write a pretty much drop-in replacement for util.promt().

This particular bit of code is jQuery-specific. It uses a div already existing on the page, #wmd-media-gallery, and applies jQuery UI's $.dialog() method to it, converted it into a popup modal dialog. The contents of the dialog is then loaded by AJAX. The URL that is loads is being specified in a global variable that is passed to it (WMD_IMAGE_GALLERY_URL).

util.imageGallery = function(gallery_url, makeLinkFunction){
gallery = $('#wmd-media-gallery');

if (gallery.html()) {
gallery.dialog('open');
}
else {
gallery.css('visibility', 'visible');
gallery.load(gallery_url, function(){
gallery.dialog({
title: 'Media Gallery',
bgiframe: true,
height: 550,
width: 900,
modal: true,
buttons: {
'Insert': function(){
// Enumerate images; insert those checked.
$('#wmd-media-gallery .media-insert').each(function(){
if ($(this).is(':checked')) {
img_path = $(this).attr('rel');
console.log(img_path);
makeLinkFunction(img_path);
}
});
$(this).dialog('close');
},
'Cancel': function() {$(this).dialog('close'); }
}
});
});
}
};

Pretty simple so far, right?

Well, here's the tricky part. If you notice what happens when the 'Insert' button is clicked, the code will scan the HTML of the dialog, and look for any input:checked element that has class "media-insert". For those elements which are found, it searches for ones which are checked. If a checked item is found, it will grab the Image URL out of the rel="" attribute, and pass that back to WMD editor for insertion into the edit box.

Ah, but not so fast. The problem comes in that WMD editor was not originally written to insert multiple images in such a way. With the stock code, what happens is it will inset one image inside another, thus only rendering 1 image properly, and leaving a mish-mash of code around it.

It should render this:
![alt text][1]
![alt text][2]

[1]: /some/url.jpg
[2]: /some/image.jpg
What it was rendering was this:
![alt text![alt text][1]][1]
The particular code in question lies int he command.addLinkDef() function. What needs to happen is that before that function processes the 'chunk', it must first clear the settings from the previous image out of it.

var getLink = function(wholeMatch, link, id, end){
// ...
};

// This goes after the getLink function

if (chunk.after.substring(0,2) == "][") {
chunk.before += chunk.selection + chunk.after.substring(0,2);
chunk.after = chunk.after.substring(2);
var linkEnd = chunk.after.indexOf(']');
linkEnd++;

chunk.before += chunk.after.substring(0, linkEnd);
chunk.selection = "";
chunk.after = chunk.after.substring(linkEnd + 1);
}

// ...and before the chunk.before [...] code

chunk.before = chunk.before.replace(regex, getLink);

And there you have it, you can now run custom image galleries from WMD editor. I'll leave it up to your imagination as to what you can do with that, but here's what mine ended up looking like:

Editor Window

Photobucket


Inserted Image
Photobucket

If you noticed, the django-uploadify app is being used in the gallery (hence why I began working on it).

  © Blogger template 'Minimalist G' by Ourblogtemplates.com 2008

Back to TOP