a work on process

Using the Django ORM as a standalone component

You are reading a post by James Stewart entitled Using the Django ORM as a standalone component. It was posted on 18 February 2008 at 11:55 pm.

You can find more posts by returning to the index.

Filed under: Notes
Tagged: , , , , , ,

Django logoI’ve found myself working in Python lately, both for a new project and while preparing a review of the Django book. Working in Ruby I’ve become used to relying on ActiveRecord whenever I need to talk to a database (whether inside Rails or not) and after a little time refamiliarising myself with MySQLdb I realised I was going to need a decent ORM for this project. As well as being road-tested and well documented, I was also looking for something that could either generate its models on the fly, or had a tool to generate them from an existing schema.

I checked out SQLAlchemy and SQLObject, both of which looked like worthy contendors, but couldn’t find the generator I was looking for (if you know of one, please do let me know in the comments!) so I switched over to Django. I couldn’t find much information on using their ORM standalone, so thought I should share what I discovered. Please bear in mind that my python is rather rusty–if there are better ways to do any of this I’d be very pleased to hear about it.

The tool to generate your model classes from an existing database is django-admin.py which should be in your path if you’ve got Django installed. To get that up and running you’re going to need to set a few options.

First up, you’ll need a settings.py file specifying your database details. Mine looks like:

DATABASE_ENGINE = 'mysql'
DATABASE_NAME = 'mydatabase'
DATABASE_USER = 'myusername'
DATABASE_PASSWORD = 'mypassword'

Once that is done and saved, then from the command line you should be able to call:

django-admin.py inspectdb --settings=settings

and the models will be echoed to stdout. To redirect that to a file called models.py you’ll need:

django-admin.py inspectdb --settings=settings > models.py

I found a few areas where the generated objects threw errors. We have a column called ‘try’ which is a python keyword, so that required a small change to the code. And a number of models have foreign key relationships with other models that are declared after them, so a little reorganising was called for. It’d be really nice to have the script handle that, but it wasn’t a big deal to make the changes by hand.

With that done, I tried a very simple new script:

from models import *
a = MyModel.objects.all() 
print a

But ran into a few issues:

The ORM is relying on the environment variable DJANGO_SETTINGS_MODULE to tell it where to find your database credentials. You’ll need to set that to point to the settings.py file you created earlier.

You can’t have your models.py file in the same folder as your test script. Doing so throws a “IndexError: list index out of range” error. Instead make a new folder called, say, orm and put models.py in it, along with an empty file called __init__.py which will tell python to treat the folder as a module. You can then update your test script to:

from orm.models import *
a = MyModel.objects.all() 
print a

With that done, you should be able to use the ORM just as you would in your Django view code.

Recommend this post:

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Related Posts

 

9 Comments

  • For SQLObject (not exactly like Django’s, more like ActiveRecord): http://www.sqlobject.org/SQLObject.html#automatic-class-generation

    Comment by Ian Bicking — 19 February 2008 @ 2:58 am

  • Ah, great. Thanks Ian.

    Comment by James Stewart — 19 February 2008 @ 8:10 am

  • For SQLAlchemy + Elixir. Seems to be active.

    http://code.google.com/p/sqlautocode/

    Comment by Dan Farina — 19 February 2008 @ 10:16 am

  • SQLAlchemy has an included ‘SQLSoup’ plugin:
    http://www.sqlalchemy.org/docs/04/plugins.html#plugins_sqlsoup
    Like SQLObject’s fromDatabase, it introspects the database on-the-fly rather than introspecting it once and generating a models specification.

    I have paranoia about code generation in general, so that inspectdb always kind of scared me.

    Comment by Adam Gomaa — 23 February 2008 @ 12:15 pm

  • Adam – I tend to prefer introspection too, but for various reasons I wanted to go with some explicit code here. For future projects it definitely sounds like SQLAlchemy is worth some more attention.

    What is it that makes you paranoid about code generation?

    Introspection tends to seem more flexible, particularly when coupled with a separate migrations system, but I’ve found generation to be helpful on a number of occasions.

    Comment by James Stewart — 23 February 2008 @ 12:19 pm

  • Thanks for your post. In case someone will find more detail useful, here’s how I adapted your tips to set up my models.py so that it will work both as part of a Django project and standalone. My directory structure is

    db/
    __init__.py
    settings.py
    orm/
    __init__.py
    models.py

    Here’s the code at the top of my models.py

    from os.path import dirname
    import os, sys

    # HACK: Django doesn’t directly support the use of the ORM outside of
    # a Django project. If this module is imported outside of a project
    # some environment needs to be set up. See
    # http://jystewart.net/process/2008/02/using-the-django-orm-as-a-standalone-component/.
    if ‘DJANGO_SETTINGS_MODULE’ not in os.environ:
    sys.path.insert(0, (dirname(__file__) or ‘.’) + ‘/../..’) # put settings.py on path
    os.environ['DJANGO_SETTINGS_MODULE'] = ‘db.settings’

    from django.db import models

    Comment by Nathan Collins — 10 June 2008 @ 8:45 pm

  • All I get when I run the django-admin command is:

    ImportError: Could not import settings ’settings’ (Is it on sys.path? Does it have syntax errors?): No module named settings

    Comment by Chris — 10 July 2008 @ 10:55 am

  • os.environ['DJANGO_SETTINGS_MODULE'] = ‘db.settings’
    This helped me.
    Thanks a lot

    Comment by wang — 16 October 2008 @ 2:39 pm

  • Thanks James!

    If anyone has settings related problems (I did), try using the –pythonpath option to add the path to the settings file to the python path. For example, if you have a directory named ‘appDir’ which contains your settings.py file:

    django-admin.py inspectdb –pythonpath=’/usr/local/appDir/’ –settings=settings

    cheers,
    -tomread

    Comment by Tom Read — 24 November 2008 @ 6:08 pm

Sorry, the comment form is closed at this time.