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_ob
j 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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With