I created a custom application to authenticate users and have hard times to make everything work with multiple databases. Help would be much appreciated.
Basically, I create multiple Django projects and want a unique database for authentication and a custom AUTH_USER_MODEL
. The databases are declared in settings.py with two routers, one for the auth
, contenttypes
, and authentication
application, and the other router for the rest of the applications.
I successfuly migrated the custom User
model and created createsuperuser
with the option --database=auth_db
but then, when I work in the admin section an create an object in one of my applications Django throws an error :
IntegrityError at /admin/django_celery_beat/crontabschedule/add/
insert or update on table "django_admin_log" violates foreign key constraint "django_admin_log_user_id_c564eba6_fk_authentication_user_id"
DETAIL: Key (user_id)=(1) is not present in table "authentication_user".
As you can see, it says the user with ID 1 isn't created, but I'm logged with it and I'm 100% sure the custom User
model was created in the authentication
app:
root@ec00652b9b9a:/app# python manage.py migrate authentication --database=auth_db
Operations to perform:
Apply all migrations: authentication
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying authentication.0001_initial... OK
root@ec00652b9b9a:/app# python manage.py migrate contenttypes --database=auth_db
Operations to perform:
Apply all migrations: contenttypes
Running migrations:
No migrations to apply.
root@ec00652b9b9a:/app# python manage.py migrate auth --database=auth_db
Operations to perform:
Apply all migrations: auth
Running migrations:
No migrations to apply.
root@ec00652b9b9a:/app# python manage.py migrate admin --database=default
Operations to perform:
Apply all migrations: admin
Running migrations:
Applying admin.0001_initial... OK
root@ec00652b9b9a:/app# python manage.py migrate sessions --database=default
Operations to perform:
Apply all migrations: sessions
Running migrations:
Applying sessions.0001_initial... OK
Does it means Celery beat
or admin
is looking in the wrong database ? How could I investigate the issue further more ?
databases_router.py
class AuthRouter:
route_app_labels = {'auth', 'contenttypes', 'authentication'}
def db_for_write(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return 'auth_db'
return None
def db_for_read(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return 'auth_db'
return None
def allow_relation(self, obj1, obj2, **hints):
if (
obj1._meta.app_label in self.route_app_labels or
obj2._meta.app_label in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label in self.route_app_labels:
return db == 'auth_db'
return None
class AppsRouter:
def db_for_write(self, model, **hints):
return 'default'
def db_for_read(self, model, **hints):
return 'default'
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model_name=None, **hints):
return True
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': env("PROJECT_DB_NAME"),
'HOST': env("PROJECT_DB_HOST"),
'PORT': env("PROJECT_DB_PORT"),
'USER': env("PROJECT_DB_USER"),
'PASSWORD': env("PROJECT_DB_PASSWORD"),
'OPTIONS': {'sslmode': 'require',
'options': '-c search_path=public'
},
},
'auth_db': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': env("AUTHENTICATION_DB_NAME"),
'HOST': env("AUTHENTICATION_DB_HOST"),
'USER': env("AUTHENTICATION_DB_USER"),
'PORT': env("AUTHENTICATION_DB_PORT"),
'PASSWORD': env("AUTHENTICATION_DB_PASSWORD"),
'OPTIONS': {'sslmode': 'require',
'options': '-c search_path=public'
},
},
}
DATABASE_ROUTERS = ['project.databases_router.AuthRouter', 'project.databases_router.AppsRouter']
AUTH_USER_MODEL = 'authentication.User'
CodePudding user response:
I'm not sure about recent Django versions, but I do not recall Django (nor Postgres) being able to handle foreign key relationships with other databases (Django's LogEntry model relies on one)
It might be easier to omit the Django admin and write something yourself, or patch the logging model.
However I'd reassess your requirement to separate the user from the default database at all. If you're really separating the User from the context application, you probably shouldn't rely on any foreign keys to user related data either.