Skip to content

Commit

Permalink
Deprecate DjangoObjectPermissionsFilter (#6075)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpkilby authored and carltongibson committed Oct 2, 2018
1 parent 903204c commit 6618338
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 5 deletions.
7 changes: 7 additions & 0 deletions docs/api-guide/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@ The `ordering` attribute may be either a string or a list/tuple of strings.

The `DjangoObjectPermissionsFilter` is intended to be used together with the [`django-guardian`][guardian] package, with custom `'view'` permissions added. The filter will ensure that querysets only returns objects for which the user has the appropriate view permission.

---

**Note:** This filter has been deprecated as of version 3.9 and moved to the 3rd-party [`djangorestframework-guardian` package][django-rest-framework-guardian].

---

If you're using `DjangoObjectPermissionsFilter`, you'll probably also want to add an appropriate object permissions class, to ensure that users can only operate on instances if they have the appropriate object permissions. The easiest way to do this is to subclass `DjangoObjectPermissions` and add `'view'` permissions to the `perms_map` attribute.

A complete example using both `DjangoObjectPermissionsFilter` and `DjangoObjectPermissions` might look something like this.
Expand Down Expand Up @@ -388,6 +394,7 @@ The [djangorestframework-word-filter][django-rest-framework-word-search-filter]
[view-permissions-blogpost]: https://blog.nyaruka.com/adding-a-view-permission-to-django-models
[search-django-admin]: https://docs.djangoproject.com/en/stable/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields
[django-rest-framework-filters]: https://github.com/philipn/django-rest-framework-filters
[django-rest-framework-guardian]: https://github.com/rpkilby/django-rest-framework-guardian
[django-rest-framework-word-search-filter]: https://github.com/trollknurr/django-rest-framework-word-search-filter
[django-url-filter]: https://github.com/miki725/django-url-filter
[drf-url-filter]: https://github.com/manjitkumar/drf-url-filters
5 changes: 2 additions & 3 deletions docs/api-guide/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,7 @@ As with `DjangoModelPermissions` you can use custom model permissions by overrid

---

**Note**: If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests, you'll want to consider also adding the `DjangoObjectPermissionsFilter` class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions.

---
**Note**: If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests and are using django-guardian for your object-level permissions backend, you'll want to consider using the `DjangoObjectPermissionsFilter` class provided by the [`djangorestframework-guardian` package][django-rest-framework-guardian]. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.

---

Expand Down Expand Up @@ -287,3 +285,4 @@ The [Django Rest Framework Role Filters][django-rest-framework-role-filters] pac
[django-rest-framework-roles]: https://github.com/computer-lab/django-rest-framework-roles
[django-rest-framework-api-key]: https://github.com/manosim/django-rest-framework-api-key
[django-rest-framework-role-filters]: https://github.com/allisson/django-rest-framework-role-filters
[django-rest-framework-guardian]: https://github.com/rpkilby/django-rest-framework-guardian
2 changes: 2 additions & 0 deletions docs/community/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ You can determine your currently installed version using `pip show`:

* Deprecate the `Router.register` `base_name` argument in favor of `basename`. [#5990][gh5990]
* Deprecate the `Router.get_default_base_name` method in favor of `Router.get_default_basename`. [#5990][gh5990]
* Deprecate the `DjangoObjectPermissionsFilter` class, moved to the `djangorestframework-guardian` package. [#6075][gh6075]


## 3.8.x series
Expand Down Expand Up @@ -1974,3 +1975,4 @@ For older release notes, [please see the version 2.x documentation][old-release-

<!-- 3.9.0 -->
[gh5990]: https://github.com/encode/django-rest-framework/issues/5990
[gh6075]: https://github.com/encode/django-rest-framework/issues/6075
6 changes: 6 additions & 0 deletions rest_framework/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import unicode_literals

import operator
import warnings
from functools import reduce

from django.core.exceptions import ImproperlyConfigured
Expand Down Expand Up @@ -284,6 +285,11 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend):
has read object level permissions.
"""
def __init__(self):
warnings.warn(
"`DjangoObjectPermissionsFilter` has been deprecated and moved to "
"the 3rd-party django-rest-framework-guardian package.",
DeprecationWarning, stacklevel=2
)
assert is_guardian_installed(), 'Using DjangoObjectPermissionsFilter, but django-guardian is not installed'

perm_format = '%(app_label)s.view_%(model_name)s'
Expand Down
22 changes: 20 additions & 2 deletions tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import base64
import unittest
import warnings

import django
from django.contrib.auth.models import Group, Permission, User
Expand Down Expand Up @@ -417,17 +418,34 @@ def test_can_read_get_queryset_permissions(self):
self.assertEqual(response.status_code, status.HTTP_200_OK)

# Read list
def test_django_object_permissions_filter_deprecated(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
DjangoObjectPermissionsFilter()

message = ("`DjangoObjectPermissionsFilter` has been deprecated and moved "
"to the 3rd-party django-rest-framework-guardian package.")
self.assertEqual(len(w), 1)
self.assertIs(w[-1].category, DeprecationWarning)
self.assertEqual(str(w[-1].message), message)

def test_can_read_list_permissions(self):
request = factory.get('/', HTTP_AUTHORIZATION=self.credentials['readonly'])
object_permissions_list_view.cls.filter_backends = (DjangoObjectPermissionsFilter,)
response = object_permissions_list_view(request)
# TODO: remove in version 3.10
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
response = object_permissions_list_view(request)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data[0].get('id'), 1)

def test_cannot_read_list_permissions(self):
request = factory.get('/', HTTP_AUTHORIZATION=self.credentials['writeonly'])
object_permissions_list_view.cls.filter_backends = (DjangoObjectPermissionsFilter,)
response = object_permissions_list_view(request)
# TODO: remove in version 3.10
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
response = object_permissions_list_view(request)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertListEqual(response.data, [])

Expand Down

0 comments on commit 6618338

Please sign in to comment.