Изменение набора запросов ModelViewSet для запроса отношения many2many на основе разрешений django-guardian

#django #python-3.x #django-rest-framework #django-queryset #django-guardian

#django #python-3.x #django-rest-framework #django-queryset #django-guardian

Вопрос:

Я получил 2 модели, которые подключены к такому большому количеству, как вы можете видеть ниже. Чего я пытаюсь добиться, так это предоставлять пользователям людей только тогда, когда пользователь имеет по крайней мере право просмотра в списке, к которому принадлежит этот человек.

Вот мои упрощенные модели;

 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», по-прежнему получает всех пользователей (даже принадлежащих другим спискам) в конечной точке people. —Что не так с кодом?—

Обновление 3: Появившаяся функция get_obejcts_for_user не возвращает результаты должным образом, как упоминал мехамасум в комментариях. Все еще ищу причину.

Ответ №1:

Похоже, ваша ошибка вызвана тем, что вы не указали basename для своего маршрута в /app/really_simple_contact_management/urls.py :

 router.register(r'people', PersonViewSet)
  

Из документов:

basename — база, используемая для создаваемых имен URL. Если значение не задано, базовое имя будет автоматически сгенерировано на основе атрибута queryset набора представлений, если он у него есть. Обратите внимание, что если viewset не включает атрибут queryset, то вы должны указать basename при регистрации viewset.

Замените строку выше на:

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

Укажите значимую строку base_name в соответствии с вашими предпочтениями, и ошибка должна исчезнуть.


Обновить:

Вы вручную создаете и возвращаете set , но get_queryset функция ожидала фактического набора запросов Django.

Вы могли бы переписать свою функцию, используя __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)
  

Комментарии:

1. Спасибо за исправление ошибки. Но моя основная цель все еще не выполнена. Я обновлю вопрос новой ошибкой, связанной с get_queryset.

2. Спасибо за объяснение и быстрый ответ. Я успешно избавляюсь от этой ошибки. Но моя основная цель все еще не выполнена. У меня есть тестовый пользователь, который имеет доступ только к просмотру в списке 1, но все равно получает пользователей, чьи из других списков, а не только из списка 1.

3. Работает ли ваша get_objects_for_user функция должным образом? Попробуйте распечатать allowed_lists и посмотрите, содержит ли этот список только 1. Если это работает правильно, вышеупомянутое решение должно работать.

4. Вы правы. Он возвращает неверно. Я занимаюсь этим, чтобы выяснить, почему.

5. Спасибо за помощь. Я нашел проблему. Это переопределяло разрешения модели.