根据django-guardian权限为多对多关系查询修改ModelViewSet的查询集

时间:2019-03-03 14:27:02

标签: django python-3.x django-rest-framework django-queryset django-guardian

我有2个模型,它们连接成ManyToMany,如下所示。 我要达到的目标是;仅当用户在该人所属的列表上至少具有查看权限时,才向用户提供服务。

这是我的简化模型;

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)
    ...

这是我的观点;

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

更新:感谢mehamasum。用最新的更新回溯(似乎与我的get_queryset覆盖更相关)

更新2:再次感谢mehamasum。现在,我的代码可以正常运行,但是我的测试用户仅对“列表1”具有视图访问权限,仍然可以将所有用户(甚至属于其他列表)都放在人员端点上。 -代码有什么问题吗?-

更新3:出现的 get_obejcts_for_user 函数未正确返回结果,如注释中提到的mehamasum一样。仍在寻找原因。

1 个答案:

答案 0 :(得分:1)

由于未在basename中为路由指定/app/really_simple_contact_management/urls.py,因此引发了错误:

router.register(r'people', PersonViewSet)

来自docs

  

basename-用于创建的URL名称的基础。如果未设置,则基名称将基于视图集的queryset属性自动生成(如果有)。请注意,如果视图集不包含queryset属性,则在注册视图集时必须设置基本名称。

将上面的行替换为:

router.register(r'people', PersonViewSet, base_name='people',)

根据您的喜好提供一个有意义的字符串作为base_name,错误应该消失。


更新:

您正在手动构建并返回set,但是get_queryset函数期望实际的Django QuerySet

您可以使用__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)