#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. Спасибо за помощь. Я нашел проблему. Это переопределяло разрешения модели.