[Django]-Django and read-only database connections

18👍

I encountered the same issue (using Django 1.11) and this question was at the top of my Google results for it.

Your initial solution is only missing one critical piece. You need to tell Django what database models ‘C’ and ‘D’ are using. What worked for me:

class ExternalModel(models.Model):
    class Meta:
        managed = False
        abstract = True    
        app_label = 'support'

Then tell your database router how to behave when it encounters that app_label in the allow_migrate() section:

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

I’m not sure that is the most-correct-solution in the eyes of the Django team, but effect is allow_migrate() returning False for any models defined with that app_label attribute value.

The Django documentation on routers doesn’t mention this explicitly (or, at least with model code samples that make it clear how the ORM passes the value for ‘db’ to allow_migrate()), but between the ‘app_label’ and ‘managed’ attributes you can get it to work*.

* In my case the default is postgres and the read-only database is Oracle 12 via cx_Oracle.

11👍

It seems around the Django 1.10.1 timeframe, Tim Graham (the primary Django maintainer), accepted a patch that suppressed this specific exception but later withdrew the patch in favor of (roughly) the following method to work around this issue and to support read-only databases using the Django ORM.

  1. Define a database router as described in the Django documentation
    on routers
    I’ve attached an example router below that routes to a
    different database based on an ‘app’ flag in the model meta.

  2. In your routers allow_migrations method, return False for any db argument
    that corresponds to a read-only database. This prevents the migration of
    the model tables regardless of where they would be routed to.

  3. This next part is a little weird but where the rubber hits the road and
    actually answers the original question. To keep makemigrations from
    attempting to create the django_migrations table in your read-only
    database, the database traffic should not be routed. In the example
    router, that means ‘read_only’ is not in DATABASE_APPS_MAPPING.

  4. So, instead, Read-only databases are accessed explicitly with “using” (e.g. MyReadOnlyModel.objects.using(‘read_only’).all()

Django database apps router

2👍

Had the same problem.
Django is trying to create the ‘django_migrations’ table in all DBs.
This happens even if there are no models associated with the read-only DB
and all routers are pointing a different DB.

I also ended up using peewee.

👤rwms

Leave a comment