Django ограничивает доступ к объектам пользователя - PullRequest
0 голосов
/ 15 января 2019

У меня есть модели узлов и пользователей, которые принадлежат Организации. Я хочу убедиться, что Пользователь будет когда-либо видеть только экземпляры Node, принадлежащие его Организации.

Для этого я хочу переопределить диспетчер объектов Node тем, который возвращает query_set отфильтрованных результатов, принадлежащих пользователю.

На основе https://docs.djangoproject.com/en/2.1/topics/db/managers/#modifying-a-manager-s-initial-queryset соответствующий код models.py , который у меня есть ниже:

class Organisation(models.Model):
    users = models.ManyToManyField(User, related_name='organisation')
    ...

class UserNodeManager(models.Manager):
    def get_queryset(self, request):
        return super().get_queryset().filter(organisation=self.request.user.organisation.first())


class Node(models.Model):
    organisation = models.ForeignKey(
        Organisation, related_name='nodes', on_delete=models.CASCADE)

    uuid = models.UUIDField(primary_key=True, verbose_name="UUID")
    ...

    objects = UserNodeManager

views.py

class NodeListView(LoginRequiredMixin, generic.ListView):
    model = Node

EDIT Я могу добавить собственный query_set к отдельным представлениям, и это работает, как показано ниже:

views.py

class NodeListView(LoginRequiredMixin, generic.ListView):
    model = Node

    def get_queryset(self):
        return Node.objects.filter(organisation__users__id=self.request.user.pk)

Однако я намерен быть СУХИМЫМ и переопределить «основной» метод query_set в одной точке, чтобы любое представление (например, выпадающий список форм, конечная точка API) выполняло запрос, ограниченный пользователем, без дополнительного кода.

Например, я использую общие представления списка django, которые имеют форму для добавления объекта сканирования, который требует от пользователя выбрать узел, к которому принадлежит сканирование. В настоящее время в форме отображаются узлы других организаций, что противоречит необходимой мне логике разрешений.

К сожалению, переопределенное свойство Node.objects, похоже, не оказывает никакого влияния, и любой пользователь может видеть все узлы. Правильный ли я подход?

Ответы [ 3 ]

0 голосов
/ 15 января 2019

Я думаю, что проблема здесь:

objects = UserNodeManager

Вам нужно запустить UserNodeManager экземпляр следующим образом:

objects = UserNodeManager()

Кроме того, он должен выдавать ошибку при вызове метода YourModel.objects.all() (который вызывается из метода get_queryset в поле зрения), потому что когда он вызывает метод get_queryset(), он не передает request. Поэтому я думаю, что это был бы лучший подход:

class UserNodeManager(models.Manager):
    def all(self, request=None):
       qs = super(UserNodeManager, self).all()
       if request:
          return qs.filter(...)
       return qs

Или вы можете создать новый метод менеджера, подобный этому (необязательно):

class UserNodeManager(models.Manager):
    def user_specific_nodes(self, request):
       return self.get_queryset().filter(...)

Также обновите в представлении:

class NodeListView(LoginRequiredMixin, generic.ListView):
    model = Node

    def get_queryset(self):
        return Node.objects.all(self.request)  # where you can obviously use filter(...) or Model.objects.user_specific_nodes(self.request)

Обновление

из комментариев

Дело в том, что вам нужно передать request с filter() или all(). В общих представлениях метод get_queryset не передает эту информацию all(). Так что вам нужно пройти это в любом случае. Есть и другой способ - использовать промежуточное программное обеспечение, например, django-crequest . Вы можете использовать это так:

from crequest.middleware import CrequestMiddleware

class UserNodeManager(models.Manager):
    def all(self):
       qs = super(UserNodeManager, self).all()
       request = CrequestMiddleware.get_request()
       return qs.filter(...)
0 голосов
/ 18 февраля 2019

@ ruddra еще раз спасибо за ваше руководство.

Хотя ваш пример промежуточного программного обеспечения не оказал на меня никакого влияния (так как пользователь все еще мог видеть объекты других), я смог использовать это с документацией django, чтобы наконец реализовать Менеджер, похожий на:

class UserDeviceManager(models.Manager):
    def get_queryset(self):
        request = CrequestMiddleware.get_request()
        return super().get_queryset().filter(organisation=request.user.organisation)
0 голосов
/ 15 января 2019

Лучший способ достижения этого - использование групп и пользовательских разрешений. Вы можете добавить группу для каждой организации и установить правильные разрешения для этих групп на своих узлах.

Взгляните на эту статью, она может помочь: Группы пользователей с пользовательскими разрешениями в Django

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...