Ошибка Django "отношение не существует" с пользовательским классом пользователя и схемами Postgresql - PullRequest
0 голосов
/ 26 февраля 2019

Я получаю ошибку django.db.utils.ProgrammingError: relation "user" does not exist при запуске createsuperuser в проекте Django с базой данных Postgresql.

Я написал следующий маршрутизатор базы данных, чтобы указать, что таблица user (которая основана напользовательское расширение класса AbstractUser) находится в схеме users.Тем не менее, Джанго не может его найти.

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   

Маршрутизатор работает для других таблиц, не связанных с аутентификацией, поэтому я подозреваю, что это связано с другими таблицами, автоматически создаваемыми Django, когда я впервые перенес класс User (auth_group, auth_group_permissions, auth_permission, django_admin_log, django_content_type, django_session).

Однако я не уверен:

  1. Если предполагается, что маршрутизаторнаписано как я (последовательность if / elif) -> есть ли лучший способ написать маршрутизатор для более чем одной схемы?
  2. Какие имена моделей соответствуют таблицам Djangoвышеперечисленное.-> Мне удалось угадать три последних имени класса (django_admin_log, django_content_type, django_session), просмотрев каталоги django/contrib, но как мне найти их для auth_group, auth_group_permissions, auth_permission?

РЕДАКТИРОВАТЬ: на основе комментария от @Kevin, я попытался написать маршрутизаторы на основе app_label с, а не названия моделей, как показано вДокументы, создание одного маршрутизатора для каждого приложения.Я также попытался вручную указать app_label в мета-классе моего класса User (то есть app_label = 'users').

Однако первоначальная ошибка (django.db.utils.ProgrammingError: relation "user" does not exist) сохраняется при вводе имени пользователя в createsuperuser.Как еще я должен справиться с этой ситуацией в маршрутизаторе?

#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

Затем я вызываю их с settings.py в следующем порядке:

DATABASE_ROUTERS = (
                    'urbio.dbrouters.AdminRouter',
                    'urbio.dbrouters.AuthRouter', 
                    'urbio.dbrouters.ContentTypeRouter', 
                    'urbio.dbrouters.SessionRouter', 
                    'urbio.dbrouters.UsersRouter',
                    )

1 Ответ

0 голосов
/ 12 марта 2019

Решением было указать флаг --database и указать правильную схему при выполнении команды createsuperuser:

python manage.py createsuperuser --database users

Кроме того, следуя этому ответу , база данныхопределение в settings.py:

DATABASES = {

    'default': 
            {},

    'schema1': 
            {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'OPTIONS': {
                            'options': '-c search_path=schema1'
                        },
            'NAME': 'mydbname',
            'USER': 'myusername',
            'PASSWORD': '***',
            'HOST': 'my.host.address',
            'PORT': '5432',
            },

    'users': 
            {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'OPTIONS': {
                            'options': '-c search_path=users'
                        },
            'NAME': 'mydbname',
            'USER': 'myusername',
            'PASSWORD': '***',
            'HOST': 'my.host.address',
            'PORT': '5432',
            }

}
...