Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

manytomany relation does not exist. It's in a different schema

I use AbstractBaseUser together with CustomPermissionsMixin. CustomPermissionsMixin is kind of the same with django PermissionsMixin the difference is I changed related_name and related_query_name for user_permissions and groups so it won't clashing with django PermissionsMixin related_name

@python_2_unicode_compatible
class CustomPermissionsMixin(models.Model):
    """
    A mixin class that adds the fields and methods necessary to support
    Django's Group and Permission model using the ModelBackend.
    """
    is_superuser = models.BooleanField(
        _('superuser status'),
        default=False,
        help_text=_(
            'Designates that this user has all permissions without '
            'explicitly assigning them.'
        ),
    )
    groups = models.ManyToManyField(
        Group,
        verbose_name=_('groups'),
        blank=True,
        help_text=_(
            'The groups this user belongs to. A user will get all permissions '
            'granted to each of their groups.'
        ),
        related_name="%(app_label)s_%(class)s_related",
        related_query_name="%(app_label)s_%(class)ss",
    )
    user_permissions = models.ManyToManyField(
        Permission,
        verbose_name=_('student user permissions'),
        blank=True,
        help_text=_('Specific permissions for this user.'),
        related_name="%(app_label)s_%(class)s_related",
        related_query_name="%(app_label)s_%(class)ss",
    )

    class Meta:
        abstract = True
    ....

I have the same Student class in two different apps. One is in App1 and another in App2 with slightly different fields. I use postgresql. App1 is in schema public while App2 in schema krt5jdjtrx.(using django tenant schema. created programmatically) Both uses AbstractBaseUser and CustomPermissionsMixin

class Student(AbstractBaseUser, CustomPermissionsMixin):
    ...

I also use DRF DjangoModelPermissions

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
        'rest_framework.permissions.DjangoModelPermissions',

And custom authentication backend

class CustomBackend(ModelBackend):
    ....

The problem is at _get_user_permissions inside django ModelBackend. Say user_obj is of type app1.Student, user_obj.user_permissions.all().query sometimes use app1_student_user_permissions or app2_student_user_permissions. How come the query uses app2_student_user_permissions while the user_obj is indeed app1 not app2? . It'll create django.db.utils.ProgrammingError: relation does not exist.

def _get_user_permissions(self, user_obj):
    print('inside _get_user_perm !!!!!!!!!!!!!!!!!!!!!!!')
    print(user_obj)
    print(type(user_obj))
    print(user_obj.user_permissions.all().query)
    return user_obj.user_permissions.all()

this is the raw queryset

SELECT "auth_permission"."id", "auth_permission"."name", "auth_permission"."content_type_id", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "app2_student_user_permissions" ON ("auth_permission"."id" = "app2_student_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "app2_student_user_permissions"."student_id" = 1 ORDER BY "django_content_type"."app_label" ASC, "django_content_type"."model" ASC, "auth_permission"."codename" ASC

EDIT

App2 student's schema/table will not be created until some point later in the program. Since App2 student has manytomany relation to Permissions, Permissions now has app1 relation and app2 relation. I think it's registered by ManyRelatedManager. (Permissions sees these two relations as public schema)

If I do student1_of_app1.user_permissions.all(), Django will iterate over the relations that Permissions has. Including the non existing App2 table. Thus it'll create django.db.utils.ProgrammingError: relation does not exist.

However, sometimes there is no error because Django gets into app1 relation first, but sometimes Django gets into app2 relation, hence the error.

How can I prevent this from happening?

like image 205
momokjaaaaa Avatar asked Oct 18 '22 04:10

momokjaaaaa


1 Answers

I found the problem was about django tenant schemas and not django. The migrate_schema --shared actually migrates the whole makemigration files regardless of the app being shared or tenant. Both apps (shared and tenant) are registered in django_content_type table which also registered in auth_permissions. Hence, the relation doesn't exist because tenant tables are not created yet at that point but manytomany relation has been registered for Permissions.

like image 154
momokjaaaaa Avatar answered Oct 21 '22 01:10

momokjaaaaa