简体   繁体   English

如何使用 Django 正确设置自定义用户 model 和多个数据库?

[英]How to properly set up custom User model and multiple databases with Django?

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 .基本上,我创建了多个 Django 项目,并且想要一个用于身份验证的唯一数据库和一个自定义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.数据库在 settings.py 中声明,带有两个路由器,一个用于authcontenttypesauthentication应用程序,另一个路由器用于应用程序的 rest。

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:我成功迁移了自定义User model 并使用选项--database=auth_db createsuperuser ,当我在管理部分工作时,在我的一个应用程序中创建一个 object ZEF0F93C83E374876A61DA0D4 错误:

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:如您所见,它说 ID 为 1 的用户未创建,但我已使用它登录,并且我 100% 确定自定义User model 是在authentication应用程序中创建的:

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?这是否意味着 Celery beatadmin正在查找错误的数据库? How could I investigate the issue further more?我怎样才能进一步调查这个问题?

databases_router.py数据库路由器.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设置.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'

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)我不确定是否依赖最近的 Django 版本,但我不记得 Django(也不是 Postgres)能够处理与其他数据库的外键关系(Django 的LogEntry Z20F35E630DAF44DBFA4C3F68F5399 on one)

It might be easier to omit the Django admin and write something yourself, or patch the logging model.省略 Django 管理员并自己编写一些东西可能更容易,或者修补日志记录 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.如果您真的将用户与上下文应用程序分开,您可能也不应该依赖任何外键来访问用户相关数据。

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

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