Django is cool - and to be really clear if you think I mean Django Reinhardt then yes I agree he is very cool, or perhaps you think I mean Pearl Django and yes they are pretty darn cool too, but if you thought instantly of the Python "The Web framework for perfectionists with deadlines" then we're on the same page (though that means we probably both need a life).
As part of the team here we tend to develop prototypes to prove out certain technical risks and right now my favorite platform for these throw-away projects has become Django, although for some more control over low-level details Twisted is great, but a bit more work. For web applications Django has so much in the box it's very easy and remarkably quick to get going - however what we were trying to do was a little different and so one of the things we had to do was add a few pieces to the Django framework itself, which turned out to also be a lot less work than we thought. Specifically we had need of two new capabilities not included in the current Django (0.96):
- A Database field to store UUID/GUID values and also support the 'auto' property so that such a field can be used as an auto-generated primary key value.
- A Database field to store regular expressions and while these are just strings we would like to have a form validator that ensures that the text you enter is a valid regular expression.
The first was easy, we simply subclassed the standard Django CharField model field class, fixed it's length at 36 characters and used the uuid module to generate a value if the 'auto' property is set. Note that the uuid module is included in Python 2.5 but not 2.4 or previous so you'll need to download it from Ka-Ping Yee. We also ensured that if 'auto' is set then any such property is not editable in the Django admin UI - this logic was taken from the current implementation of auto properties in Django itself. The code below shows the content of a module used in a number of places in the project and specifically the class UuidField is used by our model classes.
The second was also relatively easy, though it took a little longer to find some code to crib from but the result is also shown below in the isValidRegularExpression function. The approach is pretty simple (simplistic?) and involves passing the field value through the regular expression compile function and if that throws an exception assume that the value is not a legal expression. This seems to work pretty well, certainly well enough for our purposes anyway.
from django.db.models.fields import CharField
""" A field which stores a UUID value, this may also have the Boolean
attribute 'auto' which will set the value on initial save to a new
UUID value (calculated using the UUID1 method). Note that while all
UUIDs are expected to be unique we enforce this with a DB constraint.
def __init__(self, verbose_name=None, name=None, auto=False, **kwargs):
self.auto = auto
# Set this as a fixed value, we store UUIDs in text.
kwargs['maxlength'] = 36
# Do not let the user edit UUIDs if they are auto-assigned.
kwargs['editable'] = False
kwargs['blank'] = True
CharField.__init__(self, verbose_name, name, **kwargs)
""" see CharField.get_internal_type
Need to override this, or the type mapping for table creation fails.
def pre_save(self, model_instance, add):
""" see CharField.pre_save
This is used to ensure that we auto-set values if required.
value = super(UuidField, self).pre_save(model_instance, add)
if (not value) and self.auto:
# Assign a new value for this attribute if required.
value = str(uuid.uuid1())
setattr(model_instance, self.attname, value)
from django.core import validators
def isValidRegularExpression(field_data, all_data):
""" A standard validator function that ensures that the user enters a
valid regular expression in a form field.
raise validators.ValidationError, 'Error compiling regular expression %s' % field_data
isValidRegularExpression.always_test = True
There are a few more Django tweaks as well as some tips/tricks we found that hopefully I can post over the next week or so.