Skip to content

Fix the way DjangoModelPermissions asks for the model to be checked. #6310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

emilsas
Copy link

@emilsas emilsas commented Nov 7, 2018

Description

DjangoModelPermissions always use the queryset from MyView.get_queryset() to extract the model name needed for permission verifications. In some cases, .get_queryset() method changes the queryset of the view depending on the conditions for a user.

In my particular case, I created a custom permission class that verifies if the user has a role, so in a APIView I modified the permission_classes in this order: [DjangoModelPermissions, MyCustomUserPermission]. When I was testing my view, I tried to access with a user that didn't have the role required, therefore the test failed because DjangoModelPermissions tried to obtain the queryset using get_queryset().

When I realized which the problem was, I referred to the DRF documentation finding:

DjangoModelPermissions

Using with views that do not include a queryset attribute.

If you're using this permission with a view that uses an overridden get_queryset() method there may not be a queryset attribute on the view. In this case we suggest also marking the view with a sentinel queryset, so that this class can determine the required permissions. For example:
queryset = User.objects.none() # Required for DjangoModelPermissions

So, I added a queryset attribute with and empty queryset (suggested in the docs) but DjangoModelPermission continues to ask for get_queryset().

My solution to the problem was to modify DjangoModelPermissions._queryset() to always returning the queryset attribute defined in the view, if not, returning the queryset of get_queryset() method.

Copy link
Author

@emilsas emilsas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra blank line deleted at the end of test_permissions.py

@xordoquy
Copy link
Collaborator

xordoquy commented Nov 7, 2018

So, I added a queryset attribute with and empty queryset (suggested in the docs) but DjangoModelPermission continues to ask for get_queryset().

What was the error message ?

@emilsas
Copy link
Author

emilsas commented Nov 7, 2018

The error was the same with and without the queryset attribute suggested.

That my user has not the role that I was checking in get_queryset. So if DjangoModelPermissions only uses the queryset to determine the model name, it is the same to obtain the queryset from the attribute or the method.

@xordoquy
Copy link
Collaborator

xordoquy commented Nov 7, 2018

Unfortunately this will not be consistent with how DRF works in general.
In any case, get_queryset() should take precedence over queryset because it can adapts the result based on the context.
It looks like the documentation update in #5376 missed the "Using with views that do not include a queryset attribute." section to update and reflect the fact that get_queryset() should be stated instead of queryset.

@xordoquy xordoquy closed this Nov 7, 2018
@emilsas
Copy link
Author

emilsas commented Nov 7, 2018

I understand your point.
But I want to show you my complete example, so maybe I'm using something in a wrong way.

@emilsas
Copy link
Author

emilsas commented Nov 7, 2018

@xordoquy This is other issue (#4129) that I found digging for a similar problem that my fix could help it.

@emilsas
Copy link
Author

emilsas commented Nov 8, 2018

@xordoquy I share a gist with my example of code that fails with the actual version of DjangoModelPermissions.
https://gist.github.com/emilsas/0364e1e756759be6017f19cc8fdb41e8

@xordoquy
Copy link
Collaborator

xordoquy commented Nov 8, 2018

In your gist, if the user doesn't have a provider_profile then user.provider_profile.products.all() should raise an attribute error or something like that, not return an empty queryset.

@emilsas
Copy link
Author

emilsas commented Nov 8, 2018

@xordoquy I know that raises an exception, but I have a custom permission class that verify that the user has a provider profile (OnlyProvidersPermission). So I think that checking in .get_queryset() and in my custom permission would result in duplicated code.

@emilsas
Copy link
Author

emilsas commented Nov 12, 2018

@xordoquy Hi, could you give me a response please? Thanks

@xordoquy
Copy link
Collaborator

The original issue requires a documentation update to state that get_queryset() should take precedence over queryset.
If you still think there's an issue, we'll need a simple test case that we can reproduce easily first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy