Multiple Database Config in Django 1.2
Asked Answered
B

3

20

This is hopefully an easy question.

I'm having some trouble understanding the documentation for the new multiple database feature in Django 1.2. Primarily, I cant seem to find an example of how you actually USE the second database in one of your models.

When I define a new class in my models.py how do I specify which database I intend on connecting to?

My settings.py contains something similar to -

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'modules',
        'USER': 'xxx',                      
        'PASSWORD': 'xxx',                  
    },
    'asterisk': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'users',                     
        'USER': 'xxxx',                      
        'PASSWORD': 'xxxx',                  
    }

}

Edit: I was reading the documentation on routers like a dummy. If anyone else is struggling with this just make sure you read it 2 or 3 times before giving up!

Barleycorn answered 3/9, 2010 at 15:50 Comment(0)
W
24

Yeah, it is a little bit complicated.

There are a number of ways you could implement it. Basically, you need some way of indicating which models are associated with which database.

First option

Here's the code that I use; hope it helps.

from django.db import connections

class DBRouter(object):
    """A router to control all database operations on models in
    the contrib.auth application"""

    def db_for_read(self, model, **hints):
        m = model.__module__.split('.')
        try:
            d = m[-1]
            if d in connections:
                return d
        except IndexError:
            pass
        return None

    def db_for_write(self, model, **hints):
        m = model.__module__.split('.')
        try:
            d = m[-1]
            if d in connections:
                return d
        except IndexError:
            pass
        return None

    def allow_syncdb(self, db, model):
        "Make sure syncdb doesn't run on anything but default"
        if model._meta.app_label == 'myapp':
            return False
        elif db == 'default':
            return True
        return None

The way this works is I create a file with the name of the database to use that holds my models. In your case, you'd create a separate models-style file called asterisk.py that was in the same folder as the models for your app.

In your models.py file, you'd add

from asterisk import *

Then when you actually request a record from that model, it works something like this:

  1. records = MyModel.object.all()
  2. module for MyModel is myapp.asterisk
  3. there's a connection called "asterisk" so use it instead of "default"

Second Option

If you want to have per-model control of database choice, something like this would work:

from django.db import connections

class DBRouter(object):
    """A router to control all database operations on models in
    the contrib.auth application"""

    def db_for_read(self, model, **hints):
        if hasattr(model,'connection_name'):
            return model.connection_name
        return None

    def db_for_write(self, model, **hints):
        if hasattr(model,'connection_name'):
            return model.connection_name
        return None

    def allow_syncdb(self, db, model):
        if hasattr(model,'connection_name'):
            return model.connection_name
        return None

Then for each model:

class MyModel(models.Model):
    connection_name="asterisk"
    #etc...

Note that I have not tested this second option.

Walrath answered 3/9, 2010 at 17:27 Comment(3)
Sorry for the delayed response, but this was immensely helpful!Barleycorn
Hi, I've implemented your second option. It works great except for allow_syncdb. I'll post an answer below with a working allow_syncdb for any future searchers.Joint
Thanks for this! I was having a dickens of a time trying to grok this from the django docs.Christensen
J
8

An addendum to Jordans answer above. For the second option, the allow_syncdb method works correctly as follows:

def allow_syncdb(self, db, model):
    if hasattr(model,'connection_name'):
        return model.connection_name == db
    return db == 'default'
Joint answered 15/2, 2011 at 9:0 Comment(3)
Interesting! So you're setting connection_name in the model?Walrath
Yes. And it works rather well except for ManyToMany fields where I have to specify a 'through' model otherwise Django generates the 'through' table in the default database.Joint
Wow! I will definitely make a mental note of this. Good work Rich.Barleycorn
E
3

Does the documentation on automatic database routing and manually selecting a database not help?

Eurasian answered 3/9, 2010 at 15:57 Comment(3)
I may be missing something but as far as I can tell there are no examples of how to define a model with anything besides the default database.Barleycorn
+1. Django has good documentation and the docs are almost always the first place to look.Kersey
"Django has good documentation?" I have not found this to be the case very often. Typically when I need to understand something I end up looking at the source code, either hosted locally or on djangoapi.quamquam.org/trunkColonist

© 2022 - 2024 — McMap. All rights reserved.