Маршрутизатор баз данных Django "allow_migrate_model" выбрасывает следующее: "TypeError: allow_migrate() missing 1 required positional argument: 'app_label'".

Функция "allow_migrate_model" в маршрутизаторах моей базы данных продолжает выдавать следующую ошибку, когда я пытаюсь запустить python manage.py makemigrations:


...
File "C:\Users\...\lib\site-packages\django\db\utils.py", line 262, in allow_migrate
    allow = method(db, app_label, **hints)
TypeError: allow_migrate() missing 1 required positional argument: 'app_label'

Мои маршрутизаторы выглядят следующим образом:

class BaseRouter:
    route_app_labels = {}

    db_name = ""

    def db_for_read(self, model, **hints) -> Union[str, None]:
        if model._meta.app_label in self.route_app_labels:
            return self.db_name
        return None

    def db_for_write(self, model, **hints) -> Union[str, None]:
        if model._meta.app_label in self.route_app_labels:
            return self.db_name
        return None

    def allow_relation(self, obj1, obj2, **hints) -> Union[bool, None]:
        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
    ) -> Union[bool, None]:
        if app_label in self.route_app_labels:
            return db == self.db_name
        return None


class DefaultRouter(BaseRouter):
    route_app_labels = {"auth", "contenttypes", "sessions", "admin", "myapp"}
    db_name = "default"


class LibraryRouter(BaseRouter):
    """ separate router for backend stuff """
    route_app_labels = {"library"}
    db_name = "library"

В основном это немного измененная версия, найденная на Django Docs.

Если я закомментирую allow_migrate, то makemigrations работает, однако я хотел бы модифицировать allow_migrate дальше, так что сейчас это не очень убедительный вариант. Также по какой-то причине, если переписать его в статический метод (как упоминалось здесь), он работает. Но тогда я теряю переменные, хранящиеся в self, так что тоже не оптимально...

Я работаю на Django 4.2.14 и Python 3.9.10

А также по какой-то причине, если переписать его в staticmethod.

Вероятно, вы зарегистрировали маршрутизатор как:

# settings.py

# import of DefaultRouter and LibraryRouter

# …

DATABASE_ROUTERS = [DefaultRouter, LibraryRouter]

Тогда это не экземпляр: он нацелен на него как на класс, в этом и проблема: method(…) вызывается как BaseRouter.allow_migrate(db, app_label, **hints), а не через экземпляр.

Мы можем решить эту проблему, конструируя экземпляры, например:

# settings.py

# import of DefaultRouter and LibraryRouter

# …

DATABASE_ROUTERS = [DefaultRouter(), LibraryRouter()]

Другой вариант - переместить логику на один уровень вверх: сделать ее @classmethod [python-doc]:

class BaseRouter:
    route_app_labels = {}
    db_name = ''

    @classmethod
    def db_for_read(cls, model, **hints) -> Union[str, None]:
        if model._meta.app_label in cls.route_app_labels:
            return cls.db_name
        return None

    @classmethod
    def db_for_write(cls, model, **hints) -> Union[str, None]:
        if model._meta.app_label in cls.route_app_labels:
            return cls.db_name
        return None

    @classmethod
    def allow_relation(cls, obj1, obj2, **hints) -> Union[bool, None]:
        if (
            obj1._meta.app_label in cls.route_app_labels
            or obj2._meta.app_label in cls.route_app_labels
        ):
            return True
        return None

    @classmethod
    def allow_migrate(
        cls, db, app_label, model_name=None, **hints
    ) -> Union[bool, None]:
        if app_label in cls.route_app_labels:
            return db == cls.db_name
        return None

На самом деле DATABASE_ROUTERS должен работать со строкой, но я согласен, что это, возможно, не лучший способ с точки зрения дизайна программного обеспечения: если вы переименуете класс, возможно, что строка не изменится, и таким образом она ссылается на несуществующий элемент, что само по себе не вызывает исключения, но способ был разработан так:

# settings.py

# …

DATABASE_ROUTERS = [
    'module_name.DefaultRouter',
    'module_name.LibraryRouter'
]
Вернуться на верх