How to prevent django to create "django_migrations" table in a read-only database?

Hi.

I have two databases, default (db with all the data) and a database called feriados_db (“holydays”). I just want to read some data from feriados_db; not create, update or remove any record from this db.

The problem is when I run:
python manage.py makemigrations
python manage.py migrate --database=feriados_db

Django creates django_migrations table in feriados_db.

Here is my code:

  • My settings.py:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': "reserva",
        "USER": "postgres",
        "PASSWORD": "root",
        "HOST": "127.0.0.1",
        "DATABASE_PORT": "5432",
    },

    'feriados_db': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': "feriados",
        "USER": "postgres",
        "PASSWORD": "root",
        "HOST": "127.0.0.1",
        "DATABASE_PORT": "5432",
    },
}

DATABASE_ROUTERS = ["reserva.routers.ReservaRouter"]
  • Router: My router controls operations on both of my databases. I’ve tried multiple configurations in allow_migrate function. According to the documentation, returning False makes Django to not apply any migration, so tables in both dbs are intact. But, it keeps creating django_migrations table in feriados_db.
class ReservaRouter:
    """
    - default: "reserva" db alias.  
    - feriados_db: "feriados" db alias. Sólo lectura.
    """
    def db_for_read(self, model, **hints):
        """
        Los intentos de leer modelos de la app "feriados"
        van a "feriados_db".
        """
        if model._meta.app_label == "feriados":
            return "feriados_db"
        return "default"


    def db_for_write(self, model, **hints):
        """
        Los intentos de escribir modelos de las apps van
        a la base de datos "default".
        La base de datos "feriados_db" será de sólo
        lectura.
        """
        if model._meta.app_label != "feriados":
            return "default"

        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Permite relaciones si:
        - los dos modelos son parte de la app "feriados"
        - los dos modelos no son parte de la app "feriados"
        """

        if obj1._meta.app_label == "feriados" and obj2._meta.app_label == "feriados":
            return True
        elif "feriados" not in [obj1._meta.app_label, obj2._meta.app_label]:
            return True
        return None
        

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Asegura que la migración solo se aplique en las bases de datos correctas.
        """        
        return False
  • models.py in feriados app. If I set managed = True, the router makes Django to create a table in feriados_db called “feriados” according to the model specified in “feriados” app. So, the router works correctly.
class Feriados(models.Model):
    RELIGIOSO = "Religioso"
    CIVIL = "Civil"

    TIPO_CHOICES = [
        (RELIGIOSO, "Religioso"),
        (CIVIL, "Civil"),
    ]

    fecha = models.DateField(unique=True)
    motivo = models.CharField(max_length=200)
    tipo = models.CharField(
        max_length=50,
        choices=TIPO_CHOICES,
    )

    class Meta:
        managed = False
        db_table = "feriados"
    

Maybe the origin of this problem is because when I was testing my router (specifically allow_migrate function), Django didn’t recognize it at all, so when I tried to make migrations, Django used the default router. I deleted and created feriados_db and tried another configuration for the router, again and again. Deleting 0001_initial.py inside the feriados/migrations directory fixed the issue. So, that, perharps, caused Django to have a conflict with migrations?

TL;DR: I don’t want django_migrations table in my read-only database.

Welcome @sqr !

Just don’t run any migrations against it. If those models exist, and you aren’t going to manage the schema using Django, then you don’t need to do it.

Migrations aren’t mandatory, you only need to use them when you want Django to manage the schema.

2 Likes

Thanks for helping me.

Managing the schema means creating, updating and deleting records, right? Well, I’ll keep managed=False, because the db is read-only.

Please, tell me if I did wrong, but, in order to make queries to “feriados_db” and retrieve data, I created the “feriados” app and then used django-admin inspectdb --database feriados_db to create the model. Is this enough to make queries like Feriados.objects.all()?

So, will Django always create the django_migrations table?

Not quite. A reference to the “schema” in a database is talking about the structure of the tables themselves. So “managing the schema” means creating, modifying, and deleting tables, not the data within those tables.

Yes! There is no need to run a makemigrations or migrate.

If you run migrate, yes. That table is how Django tracks which migrations have been run on that database.

1 Like