[Django] #31093: Extend permission backend with get_queryset(user, model)

20 views
Skip to first unread message

Django

unread,
Dec 15, 2019, 9:24:52 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
----------------------------------------+------------------------
Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
----------------------------------------+------------------------
Permissions on objects are based on two mechanisms that developers have to
implement:

- filtering a queryset based on a user object and eventually a permission
name
- returning if a user has a permission on an object instance

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,
MRSRequest):
return False

return (
user_obj.profile == 'admin'
or obj.caisse in user_obj.caisses.all()
)
}}}

However, permission framework does not include a the first security
feature mentioned: getting a filtered queryset with objects a user should
be able to see, eventually for a given permission. Such implementation
could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):
if not queryset.model == MRSRequest:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return queryset.filter(caisse__in=user_obj.caisses.all())
}}}

The admin views could use this, and django.contrib.auth could provide
generic views extensions which do check permissions.

--
Ticket URL: <https://code.djangoproject.com/ticket/31093>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 15, 2019, 9:26:49 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

New description:

Permissions on objects are based on two mechanisms that developers have to
implement:

- returning if a user has a permission on an object instance


- filtering a queryset based on a user object and eventually a permission
name

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,
MRSRequest):
return False

return (
user_obj.profile == 'admin'
or obj.caisse in user_obj.caisses.all()
)
}}}

However, permission framework should also allow developers to implement
the second security mechanism: getting a filtered queryset with objects a


user should be able to see, eventually for a given permission. Such
implementation could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):
if not queryset.model == MRSRequest:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return queryset.filter(caisse__in=user_obj.caisses.all())
}}}

The admin views could use this, and django.contrib.auth could provide
generic views extensions which do check permissions.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:1>

Django

unread,
Dec 15, 2019, 9:28:32 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

> Permissions on objects are based on two mechanisms that developers have
> to implement:
>


> - returning if a user has a permission on an object instance
> - filtering a queryset based on a user object and eventually a permission
> name
>
> Currently, permission backend allows developers to implement the first
> mechanism: you can allow a specific permission on an object with the
> permission backend.
>
> This works extremely well even for complex use cases: you get an model
> object, a user, a permission name and you can return True.
>
> Exemple:
>
> {{{
> def has_perm(self, user_obj, perm, obj=None):
> if not user_obj.is_authenticated or not isinstance(obj,
> MRSRequest):
> return False
>
> return (
> user_obj.profile == 'admin'
> or obj.caisse in user_obj.caisses.all()
> )
> }}}
>

> However, permission framework should also allow developers to implement

> the second security mechanism: getting a filtered queryset with objects a


> user should be able to see, eventually for a given permission. Such
> implementation could look like:
>

> {{{
> def filter_queryset(self, user_obj, perm, queryset=None):
> if not queryset.model == MRSRequest:
> return queryset
>
> if not user_obj.is_authenticated:
> return queryset.none()
>
> return queryset.filter(caisse__in=user_obj.caisses.all())
> }}}
>
> The admin views could use this, and django.contrib.auth could provide
> generic views extensions which do check permissions.

New description:

Permissions on objects are based on two mechanisms that developers have to
implement:

- returning if a user has a permission on an object instance


- filtering a queryset based on a user object and eventually a permission
name

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,
MRSRequest):
return False

return (
user_obj.profile == 'admin'
or obj.caisse in user_obj.caisses.all()
)
}}}

However, permission framework should also allow developers to implement
the second security mechanism: getting a filtered queryset with objects a


user should be able to see, eventually for a given permission. Such
implementation could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):
if not queryset.model == MRSRequest:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return queryset.filter(caisse__in=user_obj.caisses.all())
}}}

The admin views could use this, and django.contrib.auth could provide

generic views extensions which do check permissions, removing the need to
share a mixin that just does return a Mixin with a get_queryset method to
complement the code that they have in the permission backend. It would
reduce chances to make a mistake when updating permission code if it's all
at the same place, an opinion that I consider suited for a framework like
Django.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:2>

Django

unread,
Dec 15, 2019, 9:31:51 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

> Permissions on objects are based on two mechanisms that developers have
> to implement:
>


> - returning if a user has a permission on an object instance
> - filtering a queryset based on a user object and eventually a permission
> name
>
> Currently, permission backend allows developers to implement the first
> mechanism: you can allow a specific permission on an object with the
> permission backend.
>
> This works extremely well even for complex use cases: you get an model
> object, a user, a permission name and you can return True.
>
> Exemple:
>
> {{{
> def has_perm(self, user_obj, perm, obj=None):
> if not user_obj.is_authenticated or not isinstance(obj,
> MRSRequest):
> return False
>
> return (
> user_obj.profile == 'admin'
> or obj.caisse in user_obj.caisses.all()
> )
> }}}
>

> However, permission framework should also allow developers to implement

> the second security mechanism: getting a filtered queryset with objects a


> user should be able to see, eventually for a given permission. Such
> implementation could look like:
>

> {{{
> def filter_queryset(self, user_obj, perm, queryset=None):
> if not queryset.model == MRSRequest:
> return queryset
>
> if not user_obj.is_authenticated:
> return queryset.none()
>
> return queryset.filter(caisse__in=user_obj.caisses.all())
> }}}
>
> The admin views could use this, and django.contrib.auth could provide

> generic views extensions which do check permissions, removing the need to
> share a mixin that just does return a Mixin with a get_queryset method to
> complement the code that they have in the permission backend. It would
> reduce chances to make a mistake when updating permission code if it's
> all at the same place, an opinion that I consider suited for a framework
> like Django.

New description:

Permissions on objects are based on two mechanisms that developers have to
implement:

- returning if a user has a permission on an object instance


- filtering a queryset based on a user object and eventually a permission
name

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,

SomeModel):
return False

return (
user_obj.profile == 'admin'

or obj.related_model_fk in user_obj.related_model_m2m.all()
)
}}}

However, permission framework should also allow developers to implement

the second security mechanism: getting a filtered queryset with objects a


user should be able to see, eventually for a given permission. Such
implementation could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):

if not queryset.model == SomeModel:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return
queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())
}}}

The admin views could use this, and django.contrib.auth could provide

generic views extensions which do check permissions, removing the need to
share a mixin that just does return a Mixin with a get_queryset method to
complement the code that they have in the permission backend. It would
reduce chances to make a mistake when updating permission code if it's all
at the same place, an opinion that I consider suited for a framework like
Django.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:3>

Django

unread,
Dec 15, 2019, 9:36:24 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

> Permissions on objects are based on two mechanisms that developers have
> to implement:
>


> - returning if a user has a permission on an object instance
> - filtering a queryset based on a user object and eventually a permission
> name
>
> Currently, permission backend allows developers to implement the first
> mechanism: you can allow a specific permission on an object with the
> permission backend.
>
> This works extremely well even for complex use cases: you get an model
> object, a user, a permission name and you can return True.
>
> Exemple:
>
> {{{
> def has_perm(self, user_obj, perm, obj=None):
> if not user_obj.is_authenticated or not isinstance(obj,

> SomeModel):


> return False
>
> return (
> user_obj.profile == 'admin'

> or obj.related_model_fk in user_obj.related_model_m2m.all()
> )
> }}}
>
> However, permission framework should also allow developers to implement

> the second security mechanism: getting a filtered queryset with objects a


> user should be able to see, eventually for a given permission. Such
> implementation could look like:
>

> {{{
> def filter_queryset(self, user_obj, perm, queryset=None):

> if not queryset.model == SomeModel:


> return queryset
>
> if not user_obj.is_authenticated:
> return queryset.none()
>
> return

> queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())


> }}}
>
> The admin views could use this, and django.contrib.auth could provide

> generic views extensions which do check permissions, removing the need to
> share a mixin that just does return a Mixin with a get_queryset method to
> complement the code that they have in the permission backend. It would
> reduce chances to make a mistake when updating permission code if it's
> all at the same place, an opinion that I consider suited for a framework
> like Django.

New description:

Permissions on objects are based on two mechanisms that developers have to
implement:

- returning if a user has a permission on an object instance


- filtering a queryset based on a user object and eventually a permission
name

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,

SomeModel):
return False

return user_obj.is_superuser or obj.related_model_fk in
user_obj.related_model_m2m.all()
}}}

However, permission framework should also allow developers to implement

the second security mechanism: getting a filtered queryset with objects a


user should be able to see, eventually for a given permission. Such
implementation could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):

if not queryset.model == SomeModel:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return
queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())
}}}

The admin views could use this, and django.contrib.auth could provide

generic views extensions which do check permissions, removing the need to
share a mixin that just does return a Mixin with a get_queryset method to
complement the code that they have in the permission backend. It would
reduce chances to make a mistake when updating permission code if it's all
at the same place, an opinion that I consider suited for a framework like
Django.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:4>

Django

unread,
Dec 15, 2019, 9:39:58 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

> Permissions on objects are based on two mechanisms that developers have
> to implement:
>


> - returning if a user has a permission on an object instance
> - filtering a queryset based on a user object and eventually a permission
> name
>
> Currently, permission backend allows developers to implement the first
> mechanism: you can allow a specific permission on an object with the
> permission backend.
>
> This works extremely well even for complex use cases: you get an model
> object, a user, a permission name and you can return True.
>
> Exemple:
>
> {{{
> def has_perm(self, user_obj, perm, obj=None):
> if not user_obj.is_authenticated or not isinstance(obj,

> SomeModel):
> return False
>
> return user_obj.is_superuser or obj.related_model_fk in
> user_obj.related_model_m2m.all()
> }}}
>
> However, permission framework should also allow developers to implement

> the second security mechanism: getting a filtered queryset with objects a


> user should be able to see, eventually for a given permission. Such
> implementation could look like:
>

> {{{
> def filter_queryset(self, user_obj, perm, queryset=None):

> if not queryset.model == SomeModel:


> return queryset
>
> if not user_obj.is_authenticated:
> return queryset.none()
>
> return

> queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())


> }}}
>
> The admin views could use this, and django.contrib.auth could provide

> generic views extensions which do check permissions, removing the need to
> share a mixin that just does return a Mixin with a get_queryset method to
> complement the code that they have in the permission backend. It would
> reduce chances to make a mistake when updating permission code if it's
> all at the same place, an opinion that I consider suited for a framework
> like Django.

New description:

Permissions on objects are based on two mechanisms that developers have to
implement:

- returning if a user has a permission on an object instance


- filtering a queryset based on a user object and eventually a permission
name

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,

SomeModel):
return False

return user_obj.is_superuser or obj.related_model_fk in
user_obj.related_model_m2m.all()
}}}

However, permission framework should also allow developers to implement

the second security mechanism: getting a filtered queryset with objects a


user should be able to see, eventually for a given permission. Such
implementation could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):

if not queryset.model == SomeModel:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return
queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())
}}}

The admin views could use this, and django.contrib.auth could provide

generic views extensions which do check permissions, removing the need to
share a mixin that just does return a Mixin with a get_queryset method to
complement the code that they have in the permission backend. It would
reduce chances to make a mistake when updating permission code if it's all
at the same place, an opinion that I consider suited for a framework like
Django.

I consider that the subject of making ModelChoiceFields to be able to
benefit from this is out of the scope of this ticket, but I could bring it
up for discussion if this feature is implemented.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:5>

Django

unread,
Dec 15, 2019, 9:42:32 AM12/15/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model)
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: new
Component: contrib.auth | Version: 3.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Description changed by James Pic:

Old description:

> Permissions on objects are based on two mechanisms that developers have
> to implement:
>


> - returning if a user has a permission on an object instance
> - filtering a queryset based on a user object and eventually a permission
> name
>
> Currently, permission backend allows developers to implement the first
> mechanism: you can allow a specific permission on an object with the
> permission backend.
>
> This works extremely well even for complex use cases: you get an model
> object, a user, a permission name and you can return True.
>
> Exemple:
>
> {{{
> def has_perm(self, user_obj, perm, obj=None):
> if not user_obj.is_authenticated or not isinstance(obj,

> SomeModel):
> return False
>
> return user_obj.is_superuser or obj.related_model_fk in
> user_obj.related_model_m2m.all()
> }}}
>
> However, permission framework should also allow developers to implement

> the second security mechanism: getting a filtered queryset with objects a


> user should be able to see, eventually for a given permission. Such
> implementation could look like:
>

> {{{
> def filter_queryset(self, user_obj, perm, queryset=None):

> if not queryset.model == SomeModel:


> return queryset
>
> if not user_obj.is_authenticated:
> return queryset.none()
>
> return

> queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())


> }}}
>
> The admin views could use this, and django.contrib.auth could provide

> generic views extensions which do check permissions, removing the need to
> share a mixin that just does return a Mixin with a get_queryset method to
> complement the code that they have in the permission backend. It would
> reduce chances to make a mistake when updating permission code if it's
> all at the same place, an opinion that I consider suited for a framework
> like Django.
>
> I consider that the subject of making ModelChoiceFields to be able to
> benefit from this is out of the scope of this ticket, but I could bring
> it up for discussion if this feature is implemented.

New description:

Permissions on objects are based on two mechanisms that developers have to
implement:

- returning if a user has a permission on an object instance


- filtering a queryset based on a user object and eventually a permission
name

Currently, permission backend allows developers to implement the first
mechanism: you can allow a specific permission on an object with the
permission backend.

This works extremely well even for complex use cases: you get an model
object, a user, a permission name and you can return True.

Exemple:

{{{
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_authenticated or not isinstance(obj,

SomeModel):
return False

return user_obj.is_superuser or obj.related_model_fk in
user_obj.related_model_m2m.all()
}}}

However, permission framework should also allow developers to implement

the second security mechanism: getting a filtered queryset with objects a


user should be able to see, eventually for a given permission. Such
implementation could look like:


{{{
def filter_queryset(self, user_obj, perm, queryset=None):

if not queryset.model == SomeModel:
return queryset

if not user_obj.is_authenticated:
return queryset.none()

return
queryset.filter(related_model_fk__in=user_obj.related_model_m2m.all())
}}}

The admin views could use this, and django.contrib.auth could provide

generic views extensions which do check permissions, removing the need to
share a mixin that just does return a Mixin with a get_queryset method to
complement the code that they have in the permission backend. It would
reduce chances to make a mistake when updating permission code if it's all
at the same place, an opinion that I consider suited for a framework like
Django.

I consider that the subject of making ModelChoiceFields to be able to
benefit from this is out of the scope of this ticket, but I could bring it

up for discussion if this feature is implemented (ie. DRF serializers have
a "context" variables where the request object is set by default, which
allows to do user-based validation: a pretty standard requirement).

--

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:6>

Django

unread,
Dec 16, 2019, 3:27:13 AM12/16/19
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model).
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: closed
Component: contrib.auth | Version: master
Severity: Normal | Resolution: wontfix

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------
Changes (by felixxm):

* status: new => closed
* version: 3.0 => master
* resolution: => wontfix


Comment:

Django's Admin already handles permissions properly. IMO a generic method
for filtering a queryset based on an user object (and/or a permission
name) shouldn't be added to the builtin authentication back-ends. You can
start a discussion on DevelopersMailingList if you don't agree.

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:7>

Django

unread,
Jan 10, 2020, 7:12:02 AM1/10/20
to django-...@googlegroups.com
#31093: Extend permission backend with get_queryset(user, model).
------------------------------+--------------------------------------

Reporter: James Pic | Owner: nobody
Type: New feature | Status: closed
Component: contrib.auth | Version: master
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+--------------------------------------

Comment (by James Pic):

Thank you for your feedback, discussion open on new forum :
https://forum.djangoproject.com/t/extend-permission-backend-with-get-
queryset-user-model/819

--
Ticket URL: <https://code.djangoproject.com/ticket/31093#comment:8>

Reply all
Reply to author
Forward
0 new messages