django-guardian
django-guardian copied to clipboard
get_objects_for_user not working
Hi, i have model: app/models.py:
class Cashbox(models.Model):
...
class Meta:
permissions = (
('operation_in', 'IN),
('operation_out', 'OUT'),
)
But I get different results:
>>> user = User.objects.get(pk=1)
>>> cashbox = Cashbox.objects.get(pk=1)
>>> cashbox in get_objects_for_user(user, perms=['app.operation_in', ], klass=Cashbox)
True
>>> user.has_perm('app.operation_in', cashbox)
Fasle
Django 1.9.4 django-guardian 1.4.2
Please help me on this.
Does the user actually have the permission? Is it global or specific to the cashbox object. A simple set of instructions (e.g. with the example project included) I can use to reproduce the problem would help enormously.
I'm having this problem too.
@levivm , does the user actually have the permission? Is it global or specific to the object. A simple set of instructions (e.g. with the example project included) I can use to reproduce the problem would help enormously.
get_objects_for_user(self.request.user, 'app.view_myobject')
returns all the 'myobject' existing on the database. Even if self.request.user has no permission.
@BenDevelopment , cannot reproduce. Do you can prepare a test case?
It pass for me (Django 1.10, django-guardian 1, 4, 5) in my app monitorings
:
def test_get_objects_for_user(self):
# get_objects_for_user(self.request.user, 'app.view_myobject')
monitoring = MonitoringFactory()
# No permission -> no object
qs = get_objects_for_user(self.user, 'monitorings.change_monitoring')
self.assertFalse(qs.filter(pk=monitoring.pk).exists())
# Has permission -> object exists
assign_perm('monitorings.change_monitoring', self.user, monitoring)
qs = get_objects_for_user(self.user, 'monitorings.change_monitoring')
self.assertTrue(qs.filter(pk=monitoring.pk).exists())
What misses?
object = WorkoutModel(name='test2')
object.save()
qs = get_objects_for_user(self.request.user, 'sportapp.view_workoutmodel')
exists = qs.filter(pk=object.pk).exists()
Exists returns true, and the qs list contains all the 'WorkoutModel' objects of my database
@BenDevelopment , are you use self.request.user isn't superuser? WorkoutModel use direct foreign key or generic ( https://django-guardian.readthedocs.io/en/stable/userguide/performance.html )? Which django and django-guardian do you use?
Yes I'm sure self.request.user isn't superuser. I'm using generic solution. Django version : 1.10 django-guardian verions : I use the last development version (clone from this repository). I don't use the last release version because of this issue : https://github.com/django-guardian/django-guardian/issues/453
I'm experiencing the same issue as @BenDevelopment .
@Nijhazer , do you can provide SQL queries? eg.
import logging
l = logging.getLogger('django.db.backends')
l.setLevel(logging.DEBUG)
l.addHandler(logging.StreamHandler())
Sure. Thanks for the prompt and helpful response.
- I have an object type, we'll call it
MyModel
. There are two objects of this type:summer
andwinter
. - I have a permission called
read
that is used byMyModel
. - I have a group called
Summer Group
. Using the admin panel, I assigned this group theread
permission onsummer
, but notwinter
. - I have a user, called
Johnny
. He does not have any permissions, but he does belong toSummer Group
. -
objs = get_objects_for_user(request.user, 'my app.read')
- Given that
request.user
isJohnny
, I would expect this to return onlysummer
, but it returns bothsummer
andwinter
.
Debug logs:
(0.003) SELECT "django_content_type"."id", "django_content_type"."app_label", "django_content_type"."model" FROM "django_content_type" INNER JOIN "auth_permission" ON ("django_content_type"."id" = "auth_permission"."content_type_id") WHERE ("auth_permission"."codename" = 'read' AND "django_content_type"."app_label" = 'myapp');
(0.002) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_user_user_permissions" ON ("auth_permission"."id" = "auth_user_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_user_permissions"."user_id" = 3;
(0.003) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_group_permissions" ON ("auth_permission"."id" = "auth_group_permissions"."permission_id") INNER JOIN "auth_group" ON ("auth_group_permissions"."group_id" = "auth_group"."id") INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_groups"."user_id" = 3;
(0.001) SELECT "myapp_mymodel"."id", "myapp_mymodel"."name" FROM "myapp_mymodel";
The third query returns nothing, as auth_group_permissions
is empty.
Hello,
I tried reproduce your issue, but I can't. Propably I something miss.
Here is a queries which I achieved:
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_user_user_permissions" ON ("auth_permission"."id" = "auth_user_user_permissions"."permission_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_user_permissions"."user_id" = 2; args=(2,)
(0.000) SELECT "django_content_type"."app_label", "auth_permission"."codename" FROM "auth_permission" INNER JOIN "auth_group_permissions" ON ("auth_permission"."id" = "auth_group_permissions"."permission_id") INNER JOIN "auth_group" ON ("auth_group_permissions"."group_id" = "auth_group"."id") INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") INNER JOIN "django_content_type" ON ("auth_permission"."content_type_id" = "django_content_type"."id") WHERE "auth_user_groups"."user_id" = 2; args=(2,)
(0.000) SELECT "guardian_userobjectpermission"."object_pk" FROM "guardian_userobjectpermission" INNER JOIN "auth_permission" ON ("guardian_userobjectpermission"."permission_id" = "auth_permission"."id") WHERE ("guardian_userobjectpermission"."user_id" = 2 AND "auth_permission"."content_type_id" = 11 AND "auth_permission"."codename" IN ('change_post')); args=(2, 11, 'change_post')
(0.000) SELECT "guardian_groupobjectpermission"."object_pk" FROM "guardian_groupobjectpermission" INNER JOIN "auth_group" ON ("guardian_groupobjectpermission"."group_id" = "auth_group"."id") INNER JOIN "auth_user_groups" ON ("auth_group"."id" = "auth_user_groups"."group_id") INNER JOIN "auth_permission" ON ("guardian_groupobjectpermission"."permission_id" = "auth_permission"."id") WHERE ("auth_user_groups"."user_id" = 2 AND "auth_permission"."codename" IN ('change_post') AND "auth_permission"."content_type_id" = 11); args=(2, 'change_post', 11)
Here is a code of tests: https://github.com/django-guardian/django-guardian/compare/debug-bug-415
Do you can look at it, @Nijhazer?
git clone
&& git checkout
&& python manage.py test --keepdb guardian.testapp.tests.test_bug.BugTestCase.test_bug_report -v2
@Nijhazer , @BenDevelopment , do yo use superuser as user with permissions?
Hi, have you understood this issue? It looks like I also have this problem... get_objects_for_user
returns all the model instances, not just the ones for which the user has permissions. I'm using Django 1.10.5 and django-guardian 1.4.8
@jfschaff , do you user superuser as user with/without permissions? Superuser has all permissions regardless whether you assign it to him or not.
@ad-m No, with a normal user I do get all the instances, whatever the permissions.
I think I have found the root-cause. There are global permissions for the user. There is a parameter 'accept_global_perms' in the function 'get_objects_for_user' If 'accept_global_perms' is True. You may get all the instances. Try to set 'accept_global_perms' to False , then you will get the expected result
I think anyone still having this issue should create a failing test.
I also had this issue at first, before discovering the accept_global_perms
option.
Why is this option set to True
by default? Setting it to False
restricts you more and therefore seems like a safer default (I explicitly have it set to False
everywhere I use get_objects_for_user
).
For anyone here waiting for a fix, I d like to point also, that I was able to get the right objects with
get_objects_for_user(user, permissions, any_perm=True, accept_global_perms=False)
But without specifying also any_perm=True
my tests were failing.