Django Multi-Database ValueError: "Не удается назначить объекту роли: текущий маршрутизатор базы данных предотвращает эту связь"
Я сталкиваюсь с ошибкой ValueError в моем приложении Django при попытке сохранить пользовательский объект со связанной с ним ассоциацией UserRole в интерфейсе администратора. Ошибка возникает при настройке нескольких баз данных, где как для ассоциации пользователей, так и для ролевых моделей предназначена база данных участников. Сообщение об ошибке:
ValueError: Cannot assign "<Role: Role object (67c43a2e-c4e7-4846-bd31-700bf5d35e82)>": the current database router prevents this relation.
У меня есть проект на Django с двумя базами данных: default и members. Пользователь, UserRoleAssociation и ролевые модели настроены на использование базы данных members через классы администратора. Ошибка возникает при сохранении пользовательского объекта со встроенной ассоциацией UserRole в Django admin.
Модели
# models.py
class Role(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
role_name = models.CharField(max_length=255, unique=True)
class Meta:
db_table = "roles"
class UserRoleAssociation(models.Model):
user = models.ForeignKey("User", on_delete=models.CASCADE)
role = models.ForeignKey("Role", on_delete=models.CASCADE)
def __str__(self):
return f"{self.role.role_name}"
class Meta:
unique_together = ["user", "role"]
db_table = "user_role_association"
class User(models.Model):
phone_number = models.CharField(max_length=15)
is_premium = models.BooleanField(default=False)
roles = models.ManyToManyField("Role", through=UserRoleAssociation, related_name="users")
class Meta:
db_table = "users"
app_label = "members"
base_manager_name = 'objects'
default_manager_name = 'objects'
Конфигурация администратора Я использую пользовательские MultiDBModelAdmin и MultiDBTabularInline для обеспечения работы базы данных участников:
# admin.py
class MultiDBModelAdmin(admin.ModelAdmin):
using = "members"
def save_model(self, request, obj, form, change):
obj.save(using=self.using)
def delete_model(self, request, obj):
obj._state.db = self.using
obj.delete(using=self.using)
def delete_queryset(self, request, queryset):
queryset.using(self.using).delete()
def get_queryset(self, request):
return super().get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)
def formfield_for_manytomany(self, db_field, request, **kwargs):
return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)
def _save_related(self, request, form, formsets, change):
"""Ensure related objects are saved in the correct database."""
for formset in formsets:
formset.instance._state.db = self.using # Force the database
super()._save_related(request, form, formsets, change)
class MultiDBTabularInline(admin.StackedInline):
using = "members"
def get_queryset(self, request):
return super().get_queryset(request).using(self.using)
def formfield_for_manytomany(self, db_field, request, **kwargs):
= # Tell Django to populate ManyToMany widgets using a query
# on the 'members' database.
return super().formfield_for_manytomany(
db_field, request, using=self.using, **kwargs
)
class UserRoleAssociationInline(MultiDBTabularInline):
model = UserRoleAssociation
extra = 1
@admin.register(User)
class MemberAdmin(MultiDBModelAdmin):
list_display = ["id"]
inlines = [UserRoleAssociationInline]
Ошибка возникает при сохранении пользовательского объекта со встроенной ассоциацией UserRole в интерфейсе администратора.
Убедитесь, что ваш "DatabaseRouter" допускает связь
#routers.py
class MembersRouter:
def db_for_read(self, model, **hints):
if model._meta.app_label == "members":
return "members"
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == "members":
return "members"
return None
def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == "members" and obj2._meta.app_label == "members":
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == "members":
return db == "members"
return None
**
Также убедитесь, что вы должны добавить это в свой settings.py**
DATABASE_ROUTERS = ['путь.к.маршрутизаторам.Пользовательский маршрут']
Теперь принудительно исправьте значение базы данных при сохранении встроенной модели "UserRoleSelection"
def _save_related(self, request, form, formsets, change):
for formset in formsets:
instances = formset.save(commit=False)
for obj in instances:
obj._state.db = self.using
obj.save(using=self.using)
formset.save_m2m()