Маршрутизатор баз данных 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'
]