I am getting a django.db.utils.ProgrammingError: relation "user" does not exist
error when running createsuperuser
on a Django project with a Postgresql database.
I wrote the following database router to indicate that the table user
(which is based on a custom extension of the AbstractUser
class) is in the schema users
. Even so, Django cannot find it.
from myapp.models import Class1, Class2, Class3
from users.models import User
from django.contrib.admin.models import LogEntry
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
# Include here classes (i.e. tables) that belongs to the "myapp" schema
ROUTED_MODELS_MYAPP = [Class1, Class2, Class3]
# Include here classes (i.e. tables) that belongs to the "users" schema
ROUTED_MODELS_USERS = [User, LogEntry, ContentType, Session] #classes for custom user model, and django tables `django_admin_log`, `django_content_type`, `django_session` tables
# classes for the following table names still missing from list: `auth_group`, `auth_group_permissions`, `auth_permission`.
class MyDBRouter(object):
"""
A router to place DB queries into correct schema depending on considered tables.
Sources:
https://stackoverflow.com/a/51007441/3976696
https://www.amvtek.com/blog/posts/2014/Jun/13/accessing-multiple-postgres-schemas-from-django/
"""
def db_for_read(self, model, **hints):
if model in ROUTED_MODELS_MYAPP:
return 'myapp'
elif model in ROUTED_MODELS_USERS:
return 'users'
return None
def db_for_write(self, model, **hints):
if model in ROUTED_MODELS_MYAPP:
return 'myapp'
elif model in ROUTED_MODELS_USERS:
return 'users'
return None
The router works for other tables unrelated to authentication, so I suspect this has to do with the other tables automatically created by Django when I migrated the User class for the first time (auth_group
, auth_group_permissions
, auth_permission
, django_admin_log
, django_content_type
, django_session
).
However, I'm not sure:
- If the router is supposed to be written like I did (a sequence of
if
/elif
) --> is there a better way to write a router for more than one schema? - Which are the model names corresponding to the
Django tables listed above. --> I was able to guess the three last class names (
django_admin_log
,django_content_type
,django_session
) by looking intodjango/contrib
directories, but how am I supposed to find those forauth_group
,auth_group_permissions
,auth_permission
?
EDIT: based on the comment from @Kevin, I tried writing the routers based on app_label
s rather than model names, as shown in the docs, making one router for each app involved. I also tried manually specifying the app_label
in the Meta class of my User class (i.e. app_label = 'users'
).
However the original error (django.db.utils.ProgrammingError: relation "user" does not exist
) persists when I enter a username in createsuperuser
. How else am I supposed to handle this situation in the router?
#Route all models in admin application, cf. https://docs.djangoproject.com/en/2.1/topics/db/multi-db/
class AdminRouter:
"""
A router to control all database operations on models in the admin application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read admin models go to users.
"""
if model._meta.app_label == 'admin':
return 'users'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write admin models go to users.
"""
if model._meta.app_label == 'admin':
return 'users'
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the admin app only appears in the 'users' database.
"""
if app_label == 'admin':
return db == 'users'
return None
class AuthRouter:
"""
A router to control all database operations on models in the
auth application.
"""
<similar to previous router>
class ContentTypeRouter:
"""
A router to control all database operations on models in the
contenttype application.
"""
<similar to previous router>
class SessionRouter:
"""
A router to control all database operations on models in the
sessionapplication.
"""
<similar to previous router>
#Route all models in users application, cf. https://docs.djangoproject.com/en/2.1/topics/db/multi-db/
class UsersRouter:
"""
A router to control all database operations on models in the users application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read user models go to users.
"""
if model._meta.app_label == 'users':
return 'users'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write user models go to users.
"""
if model._meta.app_label == 'users':
return 'users'
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the user app only appears in the 'users' database.
"""
if app_label == 'users':
return db == 'users'
return None
Then, I call them from settings.py
in the following order:
DATABASE_ROUTERS = (
'urbio.dbrouters.AdminRouter',
'urbio.dbrouters.AuthRouter',
'urbio.dbrouters.ContentTypeRouter',
'urbio.dbrouters.SessionRouter',
'urbio.dbrouters.UsersRouter',
)