Monday, November 1, 2010

Runtime dynamic models with django

I've developed web apps for some years now using php, mostly old man style coding using raw PEAR. As soon as things growed up I discovered that the time to move was arrived. I've done some research and come to django framework and I loved It :) I'm still learning (I don't have any production app yet) but the alchemy is there so I think it will be my default choice soon.

So what those dynamic models are?
In django you normally create models into models.py file for each app. So you must write the model class, but this isn't the only way to define a model in django. You can define models at runtime. You basically define a new python class at runtime using the python type module

Example:
Standard model definition:
class Post(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
dynamic model definition
import type

dct = {
    "__module__": "appname.models",
    "title": models.CharField(max_length=255),
    "content": models.TextField()
}
Post = type('Post', (models.Model,), dct)

What I'm doing here is defining a new class named Post. I'm comparing the two differnt ways to define the django model. In first case I have used the common way of defining a new django model. In the second I have used the python type module to define the model at runtime. The class inherit from models.Model class and have the attributes defined into dct.  This is tested to work with django 1.2.3. The dictnonary dct, contains all class attrs, so it can contain custom method also and even more. Note the "__module__" key: it is needed by the django admin interface to work and probably by something else so don't forget to put it. The value appname.models is refered to the model.py module where to put the runtime defined class. Note also that syncdb won't sync dynamic defined models so you must already have the model table on database.

Example:
def post_unicode(self):
    return self.name

dct['__unicode__'] = post_unicode

We can even register the new defined type to the django admin interface
admin.site.register(Post)

I've discovered about dynamic models running on this page http://code.djangoproject.com/wiki/DynamicModels. The writer complain about the fact that this technique is not applicable to django >= 1 but it worked very well in my experiments. Only note that I've added __module__ key to the dict used to build the dynamic type