I need to use a secondary SQLite database in a new Django project. This database is on the local filesystem but outside the Django folder. Its path is specified in a .env file at the root of the Django project.
I want Django to be able to manage migrations on that database, but I already have data in it, which I don't want to loose.
I was able to integrate the database into the Django project, and I see no error at any point. I can fetch data from the database via the Django shell. However, when I try to apply migrations, nothing happens: the database is not modified, but Django doesn't give me any error (in fact it says the migration has been applied).
Here's what I did:
- created an "archiver" app within Django
- within this app, created a
routers.pyfile with the following code:
class ArchiverDbRouter:
def db_for_read(self, model, **hints):
if model._meta.app_label in ['archiver']:
return 'archiver'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label in ['archiver']:
return 'archiver'
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label in ['archiver']:
return db == 'archiver'
return None
- configured
settings.pyto use two databases. The idea is to keep the default database for everything Django, and then the "archiver" database for the "archiver" app.
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
USER_DIR = Path(os.getenv('USER_DIR', './user'))
(...)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'archiver': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': USER_DIR / 'data/app.db',
}
}
DATABASE_ROUTERS = ['archiver.routers.ArchiverDbRouter']
- generated my models with the
inspectdbcommand:
python manage.py inspectdb --database archiver > tempmodels.py
Then tweaked those models and saved them to archiver/models.py. I removed the managed = False properties in all models.
- initialized the database
python manage.py migrate
This creates the "default" database file.
- generated the migrations for archiver
python manage.py makemigrations archiver
The 0001_initial.py migration file is created.
- applied this migration with the
--fakeflag
python manage.py migrate archiver 0001 --fake
I can see the corresponding migration saved in the django_migrations table.
At this point, I can use the Django shell and access the actual data in my "archiver" database, which seems to confirm that the routing works correctly and the database is found by Django. E.g.
>>> q = State(account="test", name="test", value="test")
>>> q.save()
Then I see that the new line (with the three "test" values) is present in the "states" table of m "archiver" database (using a third-party tool, HeidiSQL). I can also see that the modified date for the database file has been updated.
made some changes to my
models.py, by removing a field that was never used in thePostmodel.generated the migrations again
python manage.py makemigrations archiver
The migration file is created:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('archiver', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='post',
name='note',
),
]
- applied the new migration
python manage.py migrate archiver
This gives me the output:
Operations to perform:
Apply all migrations: archiver
Running migrations:
Applying archiver.0002_remove_post_note... OK
No error. I can see the corresponding migration saved in the django_migrations table.
HOWEVER, when I explore the archiver database (using HeidiSQL again), the "note" field is still present. Also, the "modified date" for the database file has NOT changed.
What am I missing?
DATABASESconnected to the rightarchiver? For example can you fetch data from thearchiverdatabase?