1

I want to create a model that will only be used by a second database in my Django project. So in theory I would have a default database that has all the apps and their models and then this new database will have a separate apps model which would be my jobs data.

The problem I am having is that whenever I migrate to the new database, it duplicates all the tables including the new table that was only meant to be in the new database. All the original contenttypes, sessions, auth etc is getting added to this new 'jobs' database. I only want the Jobdata model/table to be in the jobs database.

I've gone over the Django documentation a few times and haven't had much success with the router that I have set up.

I've also played around with a few options I found on SO but they are a bit dated and didn't detail the issue about migrating

Here is my current set up:

#models.py
#the new table/model that I want to go to a new separate database called jobs
class Jobdata(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
employer_name = models.CharField(max_length=50, blank=True)
empoyer_profile_id = models.CharField(max_length=50, blank=True)

#also in models.py
#the router class used to pick the right database
class JobDataRouter:
    '''Used to tell Django which database must use the job data model'''
    def db_for_read(self, model, **hints):
        """
        Attempts to read Jobdata models go to jobs database.
        """
        if model._meta.app_label == 'jobdata':
            return 'jobs'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write Jobdata models go to jobs database.
        """
        if model._meta.app_label == 'jobdata':
            return 'jobs'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the jobdata app is involved.
        """
        if obj1._meta.app_label == 'jobdata' or \
           obj2._meta.app_label == 'jobdata':
           return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the jobdata app only appears in the 'jobs'
        database.
        """
        if app_label == 'jobdata':
            return db == 'jobs'
        return None



#settings.py
DATABASE_ROUTERS = ['jobdata.models.JobDataRouter',]

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'django_live',
        'USER': 'postgres',
        'PASSWORD': os.environ.get('postgresuser'),
        'HOST': '127.0.0.1',
        'PORT': '5433',
    },



    'jobs': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'jobs',
        'USER': 'postgres',
        'PASSWORD': os.environ.get('postgresuser'),
        'HOST': '127.0.0.1',
        'PORT': '5433',
    },
}

1 Answers1

0

I managed to get the migrations to apply the correct model to the right database. In case anyone else has this issue, this is what worked for me:

I changed my database to use a blank default, then i renamed my primary database where I want the usual apps to go eg. users, auth etc. I called it 'main'

#settings.py
DATABASE_ROUTERS = ['jobdata.models.JobRouter',]
DATABASES = {
    'default': {},
    'main': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'django_live',
        'USER': 'postgres',
        'PASSWORD': os.environ.get('postgresuser'),
        'HOST': '127.0.0.1',
        'PORT': '5433',
    },



    'jobs': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'jobs',
        'USER': 'postgres',
        'PASSWORD': os.environ.get('postgresuser'),
        'HOST': '127.0.0.1',
        'PORT': '5433',
    },
}
'''
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

I then changed my router so that it selects either the main database or the jobs database according to the app it referring to. The Django documentation shows how to do this for the auth or contenttype apps, but i wanted to only do this for the jobdata app which has my jobs data model in it. So I switched the logic around.

#model.py I should probably put this file somewhere else, but documentation doesn't #specify
class JobRouter:
"""
A router to control all database operations on models in the
auth and contenttypes applications.
"""
route_app_labels = {'jobdata'}

def db_for_read(self, model, **hints):
    """
    Attempts to read jobdata models go to jobs database.
    """
    if model._meta.app_label not in self.route_app_labels:
        return 'main'
    return 'jobs'

def db_for_write(self, model, **hints):
    """
    Attempts to write jobdata models go to jobs database.
    """
    if model._meta.app_label not in self.route_app_labels:
        return 'main'
    return 'jobs'

def allow_relation(self, obj1, obj2, **hints):
    """
    Allow relations if a model in the jobdata apps is
    involved.
    """
    if (
        obj1._meta.app_label not in self.route_app_labels or
        obj2._meta.app_label not in self.route_app_labels
    ):
       return None
    return True

def allow_migrate(self, db, app_label, model_name=None, **hints):
    """
    Make sure the jobdata apps only appear in the
    'jobs' database.
    """
    if app_label not in self.route_app_labels:
        return db == 'main'
    return 'jobs'

It seems Django didn't like me having a default table and then this other new table.