简体   繁体   English

自定义用户类和Postgresql模式的Django“关系不存在”错误

[英]Django “relation does not exist” error with custom user class and Postgresql schemas

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. 我收到django.db.utils.ProgrammingError: relation "user" does not exist在具有Postgresql数据库的Django项目上运行createsuperuser时, django.db.utils.ProgrammingError: relation "user" does not exist错误。

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 . 我编写了以下数据库路由器,以指示表user (基于AbstractUser类的自定义扩展名)在架构users Even so, Django cannot find it. 即使这样,Django也找不到它。

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 ). 路由器可用于与身份验证无关的其他表,因此我怀疑这与Django首次迁移User类时自动创建的其他表有关( auth_groupauth_group_permissionsauth_permissiondjango_admin_logdjango_content_typedjango_session )。

However, I'm not sure: 但是,我不确定:

  1. 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? 如果应该像我一样写路由器(一系列if / elif )->是否有更好的方法为多个模式编写路由器?
  2. Which are the model names corresponding to the Django tables listed above. 与上面列出的Django表相对应的型号名称。 --> I was able to guess the three last class names ( django_admin_log , django_content_type , django_session ) by looking into django/contrib directories, but how am I supposed to find those for auth_group , auth_group_permissions , auth_permission ? ->通过查看django/contrib目录,我能够猜出最后三个类名( django_admin_logdjango_content_typedjango_session ),但是我应该如何找到auth_groupauth_group_permissionsauth_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. 编辑:基于@Kevin的评论,我尝试根据app_label而不是型号名称编写路由器,如文档所示,为涉及的每个应用程序制作一个路由器。 I also tried manually specifying the app_label in the Meta class of my User class (ie app_label = 'users' ). 我还尝试在User类的Meta类中手动指定app_label (即app_label = 'users' )。

However the original error ( django.db.utils.ProgrammingError: relation "user" does not exist ) persists when I enter a username in createsuperuser . 但是,当我在createsuperuser输入用户名时,原始错误( django.db.utils.ProgrammingError: relation "user" does not exist )仍然存在。 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: 然后,我按以下顺序从settings.py调用它们:

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

The solution was to specify the --database flag and point to the correct schema when running the createsuperuser command: 解决方案是在运行createsuperuser命令时指定--database标志并指向正确的架构:

python manage.py createsuperuser --database users

Also, following this answer , the database definition in settings.py is: 另外,遵循此答案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',
            }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM