Fun with Oracle and External Data

I’m playing around today with Django and Oracle, connecting my application to data from another application.

First thing I realized is that I cannot use a table or view that does not have a single column primary key.  Without a primary key, the Django Admin system complains loudly.  For those that do have a good key, it’s pretty easy to declare it to Django:

id_number = models.CharField(max_length=10,primary_key=True)

This will override Django’s default behavior of using ‘ID’ as the primary key field name.

Next, there’s a specific way that one declares the schema and table/view name for the existing structure.  Each has to be in quotes, with the entire name also in quotes.  Something like this:

    class Meta:
        db_table = u'"SCHEMA"."TABLE"'

Something else that I needed to do was to not allow changes to the external data.  This is enforced by Oracle security, but I also wanted to make it clear in my code that saves and deletes are not going to happen.  To do this, I create an abstract class upon which my other models are based, which includes the redefined save() and delete() methods that raise a NotImplemeted error.  These produce a nice, big error page when DEBUG=TRUE.

class AdvanceBase(models.Model):
    """
    Abstract base class for accessing tables and views in the external schema
    """

    class Meta:
        abstract = True

    def save(self): # No saving allowed
        raise NotImplementedError

    def delete(self): # No deletes allowed
        raise NotImplementedError

I decided to try setting up a relationship between two of the external tables.  This wasn’t really different than any other foreign key, with one exception.  I wanted to rename the field to follow Django conventions.  Orginally called SCHOOL_CODE, I changed it to SCHOOL – same as the foreign key object.  In order to still map to the correct DB column, the db_column attribute is used to declare the original name:

school = models.ForeignKey(School,blank=True,null=True,db_column='SCHOOL_CODE')

One more experiment – using a manager.  In this case I wanted to filter a table to include only living people.   The fact that I was using an external table did not change the method for this:

class PersonManager(models.Manager):
    def get_query_set(self):
        return super(PersonManager, self).get_query_set().filter(status='A')

Something else I learned was that the Django Admin will use the first manager listed for a model.  By placing the reference to the PersonManager ahead of the normal objects, the Admin only showed living people.

I’m sure there will be more later as I dig deeper into using external data.  I have an actual application related goal driving my interest, so I should get this solved soon.

As always, leave your comments below.

Applications, Models, Properties, and Circular Imports

I’ve been fighting a problem in my Django project for a while, and the solution I came up with seemed like I was settling for practicality over elegance.  This post is an attempt to rationalize my choices.

First, I love the idea of reusable applications.  I have incorporated a few from open source, including django photologue for the gallery, and the ease of use was amazing.  While I know that my work may not be general enough for public use, I do hope to be able to reuse some code in different parts of my project.  And who knows, maybe something useful to the world will come from it.

So, I divided my project into what seemed to be mostly independent applications, and started coding.

My problem came when I started heavy use of the @property decorator in my models.  Being able to reference a function using the dot notation is very handy (even though they aren’t available in functions that reference fields internally – like the ORM).  However, I found myself referencing models and fields in these two certain applications often, and I ended up with a circular import error.

I’d like to take a moment to point out that my Internet search on circular imports did not yield much help.  Several sites merely pointed out that a circular import was the result of poor coding, but offered no advice.  Finally, one post suggested moving the import to the end of models.py.  This solved the problem in my laptop development environment, but the same code would not run on my Dreamhost server (maybe it is importing in a different order).

Next, I tried to rewrite my property functions to reference the models from the other application only through the ORM – to avoid the need for an import.  This helped on the less complicated functions, but I couldn’t do it for the really useful, complicated ones.

My solution was to combine these two applications together.  The two are obviously very connected, and it was easy to make the case.  However, one of them could have been used in a more general setting, and now it is too specific to be presented to the public.  I guess I’ll have to earn my open source cred with something else.

The important thing here is that I am past this and am once again able to work on features instead of back end problems.

Am I being too theoretical? Are properties not the way to go? The comment section is waiting for your thoughts.