Django Multi-Database ValueError: "Cannot assign Role object: the current database router prevents this relation"

I'm encountering a ValueError in my Django application when trying to save a User object with a related UserRoleAssociation in the admin interface. The error occurs in a multi-database setup where both the UserRoleAssociation and Role models are intended to use the members database. The error message is:

ValueError: Cannot assign "<Role: Role object (67c43a2e-c4e7-4846-bd31-700bf5d35e82)>": the current database router prevents this relation.

I have a Django project with two databases: default and members. The User, UserRoleAssociation, and Role models are all configured to use the members database via admin classes. The error occurs when saving a User object with an inline UserRoleAssociation in the Django admin.

Models

# 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'

Admin Configuration I use a custom MultiDBModelAdmin and MultiDBTabularInline to enforce the members database:

# 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]

The error occurs when saving a User object with a UserRoleAssociation inline in the admin interface.

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