I got 2 models which are connected as ManyToMany as you can see below. The thing i'm trying to achive is; serve people to users only when a user has a at least view right on the list that person belongs.
Here is my simplified models;
class List(TimeStampedModel, UserAwareModel):
"""Model definition for List."""
name = models.CharField(_('list name'), max_length=50)
...
class Person(TimeStampedModel, UserAwareModel):
"""Model definition for Person."""
member = models.ManyToManyField(List, blank=True)
...
Here is my my views;
class ListViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Lists to be viewed or edited.
"""
queryset = List.objects.all()
serializer_class = ListSerializer
permission_classes = (CustomObjectPermissions, DjangoModelPermissions)
filter_backends = (filters.DjangoObjectPermissionsFilter,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class PersonViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows People to be viewed or edited.
"""
# queryset = Person.objects.all().order_by('-created')
serializer_class = PersonSerializer
permission_classes = (DjangoModelPermissions, )
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get_queryset(self):
user = self.request.user
allowed_lists = get_objects_for_user(user, ('view_list'), klass=List)
queryset = set()
for lst in allowed_lists:
queryset.add(Person.objects.filter(member=lst))
return queryset
Update: Thanks to mehamasum. Update the traceback with recent one (and seems more related with my get_queryset override)
Update 2: Thanks again to mehamasum. Now my code works without any error but my test user who has only view access on 'List 1' still gets all the users (those even belongs other lists) at the people endpoint. --What's the wrong with the code?--
Update 3: Appeared out get_obejcts_for_user function doesn't return results properly as mehamasum mentioned at the comments. Still searching for the reason.
Looks like your error is thrown because you didn't specify a basename
for your route in /app/really_simple_contact_management/urls.py
:
router.register(r'people', PersonViewSet)
From the docs:
basename - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the queryset attribute of the viewset, if it has one. Note that if the viewset does not include a queryset attribute then you must set basename when registering the viewset.
Replace the line above with:
router.register(r'people', PersonViewSet, base_name='people',)
Provide a meaningful string as base_name
as per your preference and the error should go away.
You are manually building and returning a set
, but the get_queryset
function expected an actual Django QuerySet.
You could rewrite your function using __in
operator:
def get_queryset(self):
user = self.request.user
allowed_lists = get_objects_for_user(user, ('view_list'), klass=List)
return Person.objects.filter(member__in=allowed_lists)