Dynamic models in Django

This module is a hack.  There’s no doubt about that.  But it’s an interesting hack, so I’m posting it and sharing the code in the hopes that it will be useful to people.  If you have a mongodb database installed as well as your regular Relational DB setup, you can use this reusable Django app to create models in the ORM dynamically.  That is, you can add them programmatically through the methods found in ga_dynamic_models.utils, and they will show up in your admin tool.  You can also use this same mechanism to dynamically add TastyPie RESTful apis, so you can create / update / delete model instances dynamically.  Furthermore, it interacts with ga_ows to allow you to create APIs that return data as GeoJSON instead of just plain old JSON if you have GeoDjango models.

So… How does it work?  This app just contains the barebones mechanisms for declaring these models.  It makes no supposition about how you’re actually going to expose that functionality to a user.  One example view is given in ga_dynamic_models.views.csv_upload, but the idea is that you will want to craft your own ways for creating models.  This framework is also generic enough to encompass anything that follows the Django ORM pattern roughly – that is, if it declares fields as part of the class declaration and optionally includes an embedded “meta” class, then this framework can be used to create those dynamically.  Oh, and by the way, actual Django Models are automagically added to the admin tool.

The one caveat is that although the tool is capable of running syncdb, it does not yet use South and therefore no migrations are available.  One could potentially do this, of course, but I haven’t gotten that far yet.  Also you must restart the server somehow after models are added or they won’t show up in the tools.  This may change when Django supports Python3 and the module cache can be invalidated, but right now, i’m not sure how to accomplish the hack of making sure that the models propagate to all worker processes.

Now that I’m done admonishing my work for it’s hackitude, however, let’s look at how one might actually declare a model:

from ga_dynamic_models.utils import *
declare_model(simple_geomodel('MyGeoModel',
 geom = simple_geofield('PointField'),
 some_name = simple_geofield('CharField', max_length=255, default='', null=True, db_index=True),
 some_integer = simple_geofield("IntegerField", default=10)
))
declare_model(simple_model("MyRegularModel",
 some_name = simple_field('CharField', max_length=255, default='', null=True, db_index=True),
 some_integer = simple_field("IntegerField", default=10)
))

And this is how you would declare a TastyPie resource:

declare_resource(simple_model_resource(
 'ga_dynamic_models.models',
 'MyRegularModel',
 "my_regular_model"
))
declare_resource(simple_geo_resource(
 'ga_dynamic_models.models',
 'MyGeoModel',
 'my_geo_model'
))

The call to declare_resource inserts the resource into the MongoDB collection.  The associated simple_* calls are simplified ways of creating the resources.  For more information and more general ways of creating resources, models, and other ORM style classes, see the project documentation and download the code on GitHub.