3

I am new to Django. I have two apps created in my project:

python3 manage.py startapp app1
python3 manage.py startapp app1

I am using Mysql as DB and I want that each app should use different schemas.

I try to follow the steps described here: Sharing (mysql) database between apps Django with Database routers

So in settings.py I defined 2 MySql schemas and keep default schema and add the add the DATABASE_ROUTERS.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app1',
    'app2',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'mydb1':{
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'APP1DB',
        'USER': 'user1',
        'PASSWORD': '****',
        'HOST': 'localhost',   # Or an IP Address that your DB is hosted on
        'PORT': '3306',
    },
    'mydb2':{
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'APP2DB',
        'USER': 'user1',
        'PASSWORD': '****',
        'HOST': 'localhost',   # Or an IP Address that your DB is hosted on
        'PORT': '3306',
    },
}

DATABASE_ROUTERS = ['app1.dbRouter.App1DBRouter', 'app2.dbRouter.App2DBRouter']

Additional files: app1/models1.py

from django.db import models

# Create your models here.

class Model1(models.Model):
    name = models.CharField(max_length=100)

app2/models2.py

from django.db import models

# Create your models here.

class Model2(models.Model):
    name = models.CharField(max_length=100)

And files: app1/dbRouter.py

class App1DBRouter(object):

    def db_for_read(self,model, **hints):
        if model._meta.app_label == 'app1':
            return 'mydb1'
        return None

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

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

    def allow_syncdb(self,db, model):
        if db == 'mydb1':
            if model._meta.app_label == 'app1':
                return True
        elif model._meta.app_label == 'app1':
            return False
        return None

app2/dbRouter.py:

class App2DBRouter(object):

    def db_for_read(self,model, **hints):
        if model._meta.app_label == 'app2':
            return 'mydb2'
        return None

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

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

    def allow_syncdb(self,db, model):
        if db == 'mydb2':
            if model._meta.app_label == 'app2':
                return True
        elif model._meta.app_label == 'app2':
            return False
        return None

After this I expect that when I run commands makemigrations and migrate I would get 2 different tables in 2 different schemas? So:

$ python3 manage.py makemigrations
Migrations for 'app1':
  app1/migrations/0001_initial.py
    - Create model Model1
Migrations for 'app2':
  app2/migrations/0001_initial.py
    - Create model Model2


$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, app1, app2, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  ...
  Applying sessions.0001_initial... OK

But there are no tables created except django_migrations in both schemas.
If I use command:

$ python3 manage.py migrate --database=mydb1

then both model tables are created in the APP1DB.

mysql> SHOW TABLES;
+----------------------------+
| Tables_in_APP1DB           |
+----------------------------+
| app1_model1                |
| app2_model2                |
| auth_group                 |

So how to solve this?

K.I.
  • 759
  • 1
  • 11
  • 30

1 Answers1

2

According to the documentation database routers may implement the method allow_migrate(db, app_label, model_name=None, **hints) in order to determine whether a certain migration should be performed or not. The methods of custom database routers are always invoked through the default database router django.db.router:

def allow_migrate(self, db, app_label, **hints):
    for router in self.routers:
        try:
            method = router.allow_migrate
        except AttributeError:
            # If the router doesn't have a method, skip to the next one.
            continue
        [...]
    return True

Because your routers don't define such a method it simply returns True at the end of the method and therefore applies the requested migration to the specified database.

You can achieve the separation of apps across the different databases by defining this method:

class App1DBRouter(object):
    [...]
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label == 'app1':
            return db == 'mydb1'
        return None

And similarly for app2.

K.I.
  • 759
  • 1
  • 11
  • 30
a_guest
  • 34,165
  • 12
  • 64
  • 118