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()
Вернуться на верх