Добавление пользователя в поле «многие ко многим» из пользовательского ввода - PullRequest
0 голосов
/ 08 февраля 2020

Я создаю функциональность, в которой модель проекта / витрины имеет администраторов ManyToManyField, которая будет содержать список пользователей, которые могут управлять проектом.

У меня возникают проблемы при добавлении пользователей в это поле ( пользователь будет получен из пользовательского ввода с внешнего интерфейса). Мне удалось назначить человека, который создает проект по умолчанию, администратором, но добавить других администраторов не удалось.

models.py

class Showcase(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField(null=True)
    skill_type = models.ForeignKey(Skill, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, related_name="Showcases")
    content = models.TextField(null=True)
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)
    voters = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="upvotes")
    slug = models.SlugField(max_length=255, unique=True)
    administrator = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="administrators", blank=True)

serializers.py

class ShowcaseAdminSerializer(serializers.ModelSerializer):

    class Meta:
        model = Showcase
        fields = ['administrator',]

С представлением ниже я хотел, чтобы только администраторы могли добавлять новых администраторов в витрину. Добавляемый пользователь будет получен из внешнего интерфейса ввода вместо URL (я надеюсь, что эта часть понятна). views.py

class showcaseAddAdminAPIView(APIView):
    '''
    Add a user as an admin to a showcase
    '''
    serializer_class = ShowcaseAdminSerializer
    permission_classes = [IsAdmin]

    def post(self, request, slug):
        showcase = get_object_or_404(Showcase, slug=slug)

        if request.user in showcase.administrator.all():
            showcase.administrator.add(user.slug)
            showcase.save()

            serializer = self.serializer_class(showcase)

            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

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

urls.py

path("<slug:slug>/addadmin/", qv.showcaseAddAdminApiview.as_view(), name="add-administrator-to-showcase"),

права доступа

class IsAdmin(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return False
        return obj.administrator == request.user

Я попытался использовать это разрешение, чтобы администратор мог добавить только администраторов. Админ на витрине. но это не работает.

Ответы [ 2 ]

1 голос
/ 11 февраля 2020

Ваше разрешение не будет работать, поскольку согласно documentation:

Обратите внимание, что общие c представления будут проверять соответствующий объект уровень разрешений, но если вы пишете свои собственные пользовательские представления, вам необходимо убедиться, что вы сами проверяете права доступа уровня объектов. Вы можете сделать это, вызвав self.check_object_permissions (request, obj) из представления, как только у вас будет экземпляр объекта. Этот вызов вызовет соответствующее APIException, если какие-либо проверки разрешений на уровне объекта не пройдут, и в противном случае просто вернется.

Таким образом, представление должно выглядеть следующим образом:

class showcaseAddAdminAPIView(APIView):  # Use CamelCase for naming class
    '''
    Add a user as an admin to a showcase
    '''
    ...

    def post(self, request, slug):
        showcase = get_object_or_404(Showcase, slug=slug)
        self.check_object_permissions(request, showcase)

Обновите класс разрешений:

class IsAdmin(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return False
        return request.user.administrators.filter(pk=obj.pk).exists()

И обновите представление:

# rest of the code
def post(self, request, slug):  # PUT is more suited for updating instance
    showcase = get_object_or_404(Showcase, slug=slug)
    try:
       self.check_object_permissions(request, showcase)
       serializer = self.serializer_class(showcase, data=request.data, partial=True)
       if serializer.is_valid():
          serializer.save()
          return Response(serializer.data, status=status.HTTP_201_CREATED)
       else:
          return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    except APIException:
        return Response(status=status.HTTP_403_FORBIDDEN)

Обновление

Переопределите update метод в сериализаторе:

class ShowcaseAdminSerializer(serializers.ModelSerializer):

   def update(self, instance, validated_data):
      users = validated_data.get('administrator')
      for user in users:
          instance.administrator.add(user)
      return instance

   # rest of the code
1 голос
/ 09 февраля 2020

Как сказал Опейеми if request.user in showcase.administrator.all(): никогда не добавит новых администраторов, если пользователь, выполняющий запрос, не является администратором, ему будет отказано, а если пользователь, выполняющий запрос, уже является администратором, он не будет добавлять ничего нового. Вам нужно передать идентификатор пользователя и использовать его для добавления нового пользователя в качестве администратора, showcase.administrator.add(user.id)

...