Skip to content

Commit

Permalink
[fix] Fixed related org field filtering in multitentant django filters
Browse files Browse the repository at this point in the history
  • Loading branch information
Aryamanz29 authored May 24, 2023
1 parent 24da2eb commit 670ec93
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 5 deletions.
6 changes: 4 additions & 2 deletions openwisp_users/api/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,15 @@ def get_queryset(self, request):
# of organizations they're related to
organization_filter = getattr(user, self._user_attr)
# if field_name organization then just organization_filter
if self.field_name == 'organization':
if self._filter_field == 'organization':
return queryset.filter(pk__in=organization_filter)
# for field_name other than organization
conditions = Q(**{'organization__in': organization_filter})
return queryset.filter(conditions)

def __init__(self, *args, **kwargs):
self._user_attr = kwargs.pop('user_attr')
self._filter_field = kwargs.pop('filter_field')
super().__init__(*args, **kwargs)


Expand Down Expand Up @@ -260,8 +261,9 @@ def filter_for_field(cls, field, name, lookup_expr='exact'):
opts = dict(
queryset=field.remote_field.model.objects.all(),
label=field.verbose_name.capitalize(),
field_name=field.name,
field_name=name,
user_attr=cls._user_attr,
filter_field=field.name,
)
if isinstance(field, ForeignKey):
return DjangoOrganizationFilter(**opts)
Expand Down
45 changes: 43 additions & 2 deletions tests/testapp/tests/test_filter_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,55 @@ def test_django_filters_by_field_other_than_organization(self):
self.assertEqual(response.data[0]['id'], lib1.id)
self.assertEqual(len(response.data), 1)
# ensure that only the 'books' belonging to 'org1'
# are visible in the django-filters select options
# and 'org1' are visible in the django-filters select options
self.assertContains(response, 'book_o1</option>')
self.assertContains(response, 'org1</option>')
self.assertNotContains(response, 'book_o2</option>')
self.assertNotContains(response, 'org2</option>')
self.assertNotContains(response, 'default</option>')
self.assertNotContains(response, 'lib1</option>')
self.assertNotContains(response, 'lib2</option>')

def test_django_filters_related_organization_field(self):
org1 = self._create_org(name='org1')
org2 = self._create_org(name='org2')
book_org1 = self._create_book(name='book_o1', organization=org1)
book_org2 = self._create_book(name='book_o2', organization=org2)
lib1 = self._create_library(name='lib1', book=book_org1)
self._create_library(name='lib2', book=book_org2)
operator = self._get_operator()
self._create_org_user(user=operator, is_admin=True, organization=org1)
token = self._obtain_auth_token(operator)
# The 'LibraryListFilter' field includes
# related organization field ('book__organization')
url = reverse('test_library_list')
response = self.client.get(
url, {'format': 'api'}, HTTP_AUTHORIZATION=f'Bearer {token}'
)
self.assertEqual(response.data[0]['id'], lib1.id)
self.assertEqual(len(response.data), 1)
# ensure that only the 'books' belonging to 'org1'
# and 'org1' are visible in the django-filters select options
self.assertContains(response, 'book_o1</option>')
self.assertContains(response, 'org1</option>')
self.assertNotContains(response, 'book_o2</option>')
self.assertNotContains(response, 'org1</option>')
self.assertNotContains(response, 'org2</option>')
self.assertNotContains(response, 'default</option>')
self.assertNotContains(response, 'lib1</option>')
self.assertNotContains(response, 'lib2</option>')
# Now ensure that filtering with the
# related organization field is properly working or not
response = self.client.get(
url, {'book__organization': org1.pk}, HTTP_AUTHORIZATION=f'Bearer {token}'
)
self.assertEqual(response.data[0]['id'], lib1.id)
self.assertEqual(len(response.data), 1)
response = self.client.get(
url, {'book__organization': org2.pk}, HTTP_AUTHORIZATION=f'Bearer {token}'
)
err = 'That choice is not one of the available choices'
self.assertEqual(response.status_code, 400)
self.assertIn(err, str(response.data['book__organization'][0]))

def test_django_filters_by_org_membership(self):
operator = self._get_operator()
Expand Down
5 changes: 4 additions & 1 deletion tests/testapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,10 @@ class TemplateDetailView(FilterByOrganizationManaged, RetrieveUpdateDestroyAPIVi
class LibraryListFilter(FilterDjangoByOrgManaged):
class Meta:
model = Library
fields = ('book',)
fields = (
'book',
'book__organization',
)


class LibraryListCreateView(FilterByOrganizationManaged, ListCreateAPIView):
Expand Down

0 comments on commit 670ec93

Please sign in to comment.