1

I have searched all over for a solution for this but have been unable to find anything.

I have one Django project, one application, two models and two database. I would like one model to speak and sync exclusively to one database. This is what I've tried:

Settings

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'database_a',                      # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': 'user',
        'PASSWORD': 'xxxxxx',
        'HOST': 'localhost',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '',                      # Set to empty string for default.
    },
    'applicationb_db': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'database_b',
        'USER': 'user',
        'PASSWORD': 'xxxxxx',
        'HOST': 'localhost',
        'PORT': '',                 
    },
}
DATABASE_ROUTERS = ['fanmode4.router.ApiRouter']

Models

from django.db import models

class TestModelA(models.Model):
    testid = models.CharField(max_length=200)
    class Meta:
        db_table = 'test_model_a'

class TestModelB(models.Model):
    testid = models.CharField(max_length=200)
    class Meta:
        db_table = 'test_model_b'
        app_label = 'application_b'

Router

class ApiRouter(object):
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'application_b':
            return 'applicationb_db'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'application_b':
            return 'applicationb_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if obj1._meta.app_label == 'application_b' or \
           obj2._meta.app_label == 'application_b':
           return True
        return None

    def allow_syncdb(self, db, model):
        if db == 'applicationb_db':
            return model._meta.app_label == 'application_b'
        elif model._meta.app_label == 'application_b':
            return False
        return None

the application name is "api". Basically with this setup, if I sync the database it will only sync on the default db. If I sync the database specifying the second database python manage.py syncdb --database=applicationb_db, it will not sync anything to the second database.

I am simply trying to achieve the following:

  • Everything for TestModelA goes to default database
  • Everything for TestModelB goes to applicationb_db database
  • Everything else goes to the default database

1 Answer 1

3

Instead of using model._meta.app_label you can use model to check which model it is and return appropriate DB.

You can update the router as:

class ApiRouter(object):
    def db_for_read(self, model, **hints):
        if model == TestModelB:
            return 'applicationb_db'
        return None

    def db_for_write(self, model, **hints):
        if model == TestModelB:
            return 'applicationb_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if model == TestModelB:
           return True
        return None

    def allow_syncdb(self, db, model):
        if model == TestModelB:
            return True
        else:
            return False
        return None
Sign up to request clarification or add additional context in comments.

4 Comments

Hi @Rohan thanks for taking time to answer. When I tried your answer I get "NameError: global name 'TestModelB' is not defined". If I try putting the model name in single quotes it just doesn't sync anything.
@MarkWinterbottom, Add from models import TestModelB in the code.
Hi Rohan, thansk a lot for your help. I don't think you can import models into the router class because I get the error "django.core.exceptions.ImproperlyConfigured: Error importing database router ApiRouter: "No module named models""
@MarkWinterbottom, Or you can change test condition in router code to if model.__name__ == 'TestModelB'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.