I have two databases defined in my setting.py
file.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'monitoring',
'USER': 'root',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '',
},
'source' :{
'ENGINE': 'django.db.backends.mysql',
'NAME': 'source_db',
'USER': '*****',
'PASSWORD': '*****',
'HOST': '*****',
'PORT': '****',
}
}
I need to access some tables in source_db which django is not allowing to do so unless I migrate the db. So, once we run command python manage.py migrate --database=source
, Django is creating some tables in server db. Since we are not allowed to create tables in server db, is there any way to stop django doing so, or any way to access tables without migrating the db?
This is the list of tables which we don't want to create.
+--------------------------------+
| Tables_in_source_db |
+--------------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| dashboard_monitoring_features |
| dashboard_monitoring_modelinfo |
| dashboard_monitoring_product |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+--------------------------------+
If you want to migrate / create tables in the default
database and not source
database, then you have to define app and database when you run migrations. Like:
python manage.py migrate dashboard --database=default
This will run migration in the dashboard
app and create tables in the default
database.
Next thing you want to do is set your source
models to non-managed. You do by specifying managed = False
in the meta class of the model:
class YourModel(models.Model):
... your fields here ...
class Meta:
managed = False
From the documentation:
If False, no database table creation or deletion operations will be performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means.
Probably nobody was clear about what the author of the question was trying to do. So let me start with the context.
By default, Django uses a database named default
. Let's say I have a CustomModel
in a CustomApp
for which the table should be created in a new database called source_db
.
Thus we have two databases: 1)default
and 2)source_db
.
We want the default tables like auth_group
required by apps like django.contrib.auth
to be created only in default
. The source_db
should have and only have tables from CustomApp
. How do we do this?
First, refer to Multiple Databases, the official documentation to understand the routing basics. Give special attention to allow_migrate()
. Let me insist, understanding of this documentation is at most important to understand the rest of this solution.
Let's begin:
In your CustomModel
, set managed = True
in the meta data:
class CustomModel(models.Model):
# your fields here ...
class Meta:
managed = True
This specifies that the table creation and alteration for this model should be taken care of by Django.
Write your CustomDBRouter
for tables in CustomApp
. (Refer to Multiple Databases for this). Don't forget to define allow_migrate()
.
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the 'CustomApp' only appear in the 'source_db' database.
"""
if app_label == 'CustomApp':
# if app=CustomApp and db=source_db, migrate
return db == 'source_db'
return None # No suggestions, ask the next router in the list
Go to your settings.py
and split the list INSTALLED_APPS
as follows:
MY_APPS = [ # List of apps defined by you
'customApp'
]
INSTALLED_APPS = [ # Full list of apps
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles'
] + MY_APPS
Now add a new router to project-app(default-app) folder (The folder where you have your settings.py
)
This router should look like:
from project.settings import MY_APPS
class DefaultDBRouter(object):
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
If an app is not defined by me, migrate only if database is 'default'
"""
if app_label not in MY_APPS:
return db == 'default'
return False
Now when adding DefaultDBRouter
to DATABASE_ROUTERS
in settings.py
, make sure that this is the last router in the list. This is at most important since the routers are processed in the order listed.
DATABASE_ROUTERS = ['customApp.dbRouter.CustomDBRouter', 'project.dbRouter.DefaultDBRouter']
Finally, you can migrate using the following commands:
python manage.py makemigrations # Make migrations for all apps
python manage.py migrate # Do migrations to 'default'
python manage.py migrate --database=source_db # Do migrations to 'source'
Now, while doing migrations follow these steps:
python manage.py makemigrations # Make migrations for all apps
python manage.py migrate # Do migrations to `default`
python manage.py migrate customApp --database=source_db
# Do migrations to 'source_db' from `customApp` only
Since tables like auth_group
do not belong to migrations of customApp
, they won't be created in the last command. You can add these 3 commands to a shell script to make your job easy. Note that, as the number of apps and databases increase, this method will look dirty. On the other hand, Solution-1 provides a clean way to do this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With