While migrating default database model assigned for another database is being migrated

-1

I was working on two database for my Django project. I followed online Django documentation and made two sqlite database work at the same time for different purposes but I ended up having one issue which is while migrating default database (python manage.py migrate) the model Game that I created for ‘games.db’ is also being migrated to ‘default.sqlite’. I have tried multiple things but nothing worked out.

Project/settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'games': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'games.db'),
    },
}

DATABASE_ROUTERS = (
    'Games.dbrouters.GamesDBRouter',
)

Games/models.py

from django.db import models
from django.urls import reverse

STATUS = (
    (1, "Publish"),
    (0, "Draft")
)


class Game(models.Model):
    title = models.CharField(max_length=2000, unique=True)
    slug = models.SlugField(max_length=2000, unique=True)
    image = models.CharField(max_length=2000, unique=True)
    overlay = models.CharField(max_length=2000, blank=True)
    updated_on = models.DateTimeField(auto_now=True)
    story_p = models.TextField(blank=True)
    story_span = models.TextField(blank=True)
    about_p = models.TextField(blank=True)
    about_span = models.TextField(blank=True)
    screenshot_1 = models.CharField(max_length=2000, blank=True)
    screenshot_2 = models.CharField(max_length=2000, blank=True)
    screenshot_3 = models.CharField(max_length=2000, blank=True)
    screenshot_4 = models.CharField(max_length=2000, blank=True)
    gameplay = models.CharField(max_length=2000, blank=True)
    download_android = models.CharField(max_length=2000, blank=True)
    download_ios = models.CharField(max_length=2000, blank=True)
    download_windows = models.CharField(max_length=2000, blank=True)
    download_linux = models.CharField(max_length=2000, blank=True)
    download_mac = models.CharField(max_length=2000, blank=True)
    torrent_android = models.CharField(max_length=2000, blank=True)
    torrent_ios = models.CharField(max_length=2000, blank=True)
    torrent_windows = models.CharField(max_length=2000, blank=True)
    torrent_linux = models.CharField(max_length=2000, blank=True)
    torrent_mac = models.CharField(max_length=2000, blank=True)
    minimum_requirements = models.TextField(max_length=2000, blank=True)
    recommended_requirements = models.TextField(max_length=2000, blank=True)
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=1)

    class Meta:
        db_table = 'games'
        ordering = ['-created_on']

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('game-detail', kwargs={
            'slug': self.slug
        })


Game.objects = Game.objects.using('games')

Games/dbrouters.py

from .models import Game

class GamesDBRouter(object):
    def db_for_read(self, model, **hints):
        if model == Game:
            return 'games'
        return None

    def db_for_write(self, model, **hints):
        if model == Game:
            return 'games'
        return None

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

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

BLUF = Looks like makemigrations/migrate applies its work via “default” DATABASE without respect for added dbrouter logic.

I just ran into this with Django==5.0.4
databases = default, write_master, and read_server1, read_server2, …
dbrouter.py routes every read to iter.cycle the list of read_server{n} databases, and all writes to the write_master.

I forgot and left the “default” database there, though its now unused.

Created a new table, added a OneToOne field on an existing model.
Successfully applied, but new tables not in PG servers (write master, replica read servers), no new column on the existing models’ tables

Table django_migrations did not show an entry for this new migration.
Command manage.py showmigrations did, and says its been applied

===> when I replaced the “default” DATABASE with a copy of the write_master, things worked:

  • manage.py could see that it needed application and did the migration
  • tables created, new columns appeared

Additional info:
My dbrouter code loops through applications labels (see code snippet).
This means that the logic controls labels like:
admin, auth, contenttypes, sessions, messages, staticfiles, … debug_toolbar, allauth, …etc

So ===> I did not have a valid “default” database (my bad) and/or I did not have enough logic to handle all cases of db router read/write/relations!

code snippet

from  django.apps import apps
app_labels = [ x.label for x in apps.get_app_configs() ]