2

I have an app (ali) on my project (website) and I wanted it to have its own database. The problem is, when I run python manage.py migrate --database=ali, the command recreates all tables within my ali database; whereas the expected result would be to have only the ali_search database.

P.S.: the application seems to be running as expected after I ran some tests. In other words, models from my ali app are being saved on the ali DB. Still, having all these empty tables inside my ali DB is not the correct way to go.

Settings:

# website.settings

...

INSTALLED_APPS = [
    'base.apps.BaseConfig',
    'ali.apps.AliConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.sites',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sitemaps',
    'django_comments',
    'mptt',
    'tagging',
    'zinnia',
]

....

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'website',
        'USER': 'website',
        'PASSWORD': 'website',
        'HOST': 'localhost',
        'PORT': '5432',
    },
    'ali': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'ali',
        'USER': 'ali',
        'PASSWORD': 'ali',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

DATABASE_ROUTERS = [
    'ali.routers.AliRouter',
]

....

Router:

# ali.routers

class AliRouter:
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'ali':
            return 'ali'
        return None

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

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

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label == 'ali':
            return db == 'ali'
        return None

Model:

# ali.models

from django.db import models

class Search(models.Model):

    results = models.IntegerField()

This is what I get by querying my ali DB with \dt:

ali=# \dt
                  List of relations
 Schema |            Name            | Type  | Owner 
--------+----------------------------+-------+-------
 public | ali_search                 | table | ali
 public | auth_group                 | table | ali
 public | auth_group_permissions     | table | ali
 public | auth_permission            | table | ali
 public | auth_user                  | table | ali
 public | auth_user_groups           | table | ali
 public | auth_user_user_permissions | table | ali
 public | django_admin_log           | table | ali
 public | django_comment_flags       | table | ali
 public | django_comments            | table | ali
 public | django_content_type        | table | ali
 public | django_migrations          | table | ali
 public | django_session             | table | ali
 public | django_site                | table | ali
 public | tagging_tag                | table | ali
 public | tagging_taggeditem         | table | ali
 public | zinnia_category            | table | ali
 public | zinnia_entry               | table | ali
 public | zinnia_entry_authors       | table | ali
 public | zinnia_entry_categories    | table | ali
 public | zinnia_entry_related       | table | ali
 public | zinnia_entry_sites         | table | ali
(22 rows)

But what I would really expect is:

ali=# \dt
                  List of relations
 Schema |            Name            | Type  | Owner 
--------+----------------------------+-------+-------
 public | ali_search                 | table | ali
(1 row)

Could it be a problem the fact that the app has the same name as the database (in this case, ali)?

FTM
  • 1,887
  • 17
  • 34

2 Answers2

7

Returning None from allow_migrate() means that the router has no opinion on the current operation. If none of the configured routers has an opinion, the default is to allow that operation. Your current router returns None for apps other than ali, so those operations are allowed on both databases.

To disallow the migrations of other apps on the ali database, you have to explicitly return False in those cases, for example:

def allow_migrate(self, db, app_label, model_name=None, **hints):
    if app_label == 'ali':
        return db == 'ali'
    return db == 'default'

Now you can just run migrate for each database, without having to specify which apps to migrate:

$ python manage.py migrate --database=default
$ python manage.py migrate --database=ali
knbk
  • 52,111
  • 9
  • 124
  • 122
  • My bad, forgot to review what I was returning from allow_migrate(). Thank you for the answer, that works perfectly! – FTM Dec 21 '18 at 08:40
0

For me, the migrate command should take a look at the routes in order to create tables. But it seems this is not the case. Therefore, it seems that the easy fix is to call migrate with the [app_label] argument. Like this:

python manage.py migrate ali --database=ali

FTM
  • 1,887
  • 17
  • 34