Django всегда обращается к базе данных по умолчанию при создании пользователей

У меня есть проект django с несколькими базами данных:

DATABASES = {
    'default': {},
    'db1': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / DB1_NAME,
    },
    'db2': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / DB2_NAME,            
    }
}

DATABASE_ROUTERS = ['app.router1.Router1', 'app.router2.Router2']

Определен маршрутизатор для db1:

class Router1:
    route_app_labels = {'app', 'sessions', 'auth', 'admin', 'contenttypes'}

    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'db1'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return 'db1'
        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 == 'db1'
        return None
<
Все работает хорошо, кроме создания новых пользователей. Когда я пытаюсь создать нового пользователя, я получаю следующую ошибку:

Когда я меняю db1 на default, создание пользователя работает нормально.

Полный отслеживание ошибок:

Traceback (most recent call last):
  File "/.venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/.venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/.venv/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/.venv/lib/python3.9/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/.venv/lib/python3.9/site-packages/rest_framework/mixins.py", line 19, in create
    self.perform_create(serializer)
  File "/.venv/lib/python3.9/site-packages/djoser/views.py", line 136, in perform_create
    user = serializer.save()
  File "/.venv/lib/python3.9/site-packages/rest_framework/serializers.py", line 212, in save
    self.instance = self.create(validated_data)
  File "/.venv/lib/python3.9/site-packages/djoser/serializers.py", line 65, in create
    user = self.perform_create(validated_data)
  File "/.venv/lib/python3.9/site-packages/djoser/serializers.py", line 72, in perform_create
    with transaction.atomic():
  File "/.venv/lib/python3.9/site-packages/django/db/transaction.py", line 197, in __enter__
    if not connection.get_autocommit():
  File "/.venv/lib/python3.9/site-packages/django/db/backends/base/base.py", line 455, in get_autocommit
    self.ensure_connection()
  File "/.venv/lib/python3.9/site-packages/django/db/backends/dummy/base.py", line 20, in complain
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.

Кажется, я нашел первопричину этой проблемы. Похоже, что перед сохранением нового пользователя создается транзакция, но эта транзакция всегда пытается получить доступ к базе данных по умолчанию. Если база данных по умолчанию не определена, возвращается вышеуказанная ошибка (в случае, если база данных по умолчанию определена, это означает, что транзакция обращается к базе данных по умолчанию, в то время как пользователи записываются в другую базу данных).

В djoser\serializers.py метод perform_create сначала создает атомарную транзакцию без аргументов:

def perform_create(self, validated_data):
    with transaction.atomic():
        user = User.objects.create_user(**validated_data)
        if settings.SEND_ACTIVATION_EMAIL:
            user.is_active = False
            user.save(update_fields=["is_active"])
    return user

Функция atomic создает его с помощью using=None:

def atomic(using=None, savepoint=True, durable=False):
    # Bare decorator: @atomic -- although the first argument is called
    # `using`, it's actually the function being decorated.
    if callable(using):
        return Atomic(DEFAULT_DB_ALIAS, savepoint, durable)(using)
    # Decorator: @atomic(...) or context manager: with atomic(...): ...
    else:
        return Atomic(using, savepoint, durable)

Затем внутри класса Atomic в методе __enter__ вызывается функция get_connection. Эта функция возвращает базу данных default в случае, если using не определена:

def get_connection(using=None):
    """
    Get a database connection by name, or the default database connection
    if no name is provided. This is a private API.
    """
    if using is None:
        using = DEFAULT_DB_ALIAS
    return connections[using]

Исправление для этого, вероятно, должно заключаться в передаче права на базу данных в функцию atomic. Как упоминалось в вопросе, переименование db1 в default обходит эту проблему.

Вернуться на верх