简体   繁体   English

Django ModelViewSet 中的过滤

[英]Filtering in Django ModelViewSet

I don't think I'm doing this correctly.我不认为我这样做是正确的。 What I'm trying to do is prevent data from being returned if it doesn't match my criteria.我想要做的是防止数据在不符合我的标准时被返回。 Here are the criteria:以下是标准:

User should be able to see the project if:如果满足以下条件,用户应该能够看到该项目:

  • If the object is private and they are the owner如果 object 是私有的并且他们是所有者

-- OR -- - 或者 -

  • The project is not private该项目不是私人的
  • If the user is the owner, or they are a member of the assigned group如果用户是所有者,或者他们是分配组的成员

EDITED PER THE COMMENT:根据评论编辑:

The code below seems to work, but I'm still not sure if this is the correct logic or the right way to do this.下面的代码似乎有效,但我仍然不确定这是否是正确的逻辑或正确的方法。

api.py api.py

class ProjectListViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all().order_by('name')
    serializer_class = ProjectLightSerializer
    authentication_classes = [TokenAuthentication, ]
    permission_classes = [IsAuthenticated, ]

    def list(self, request, *args, **kwargs):
        projects = []
        queryset = super().get_queryset()
        is_private = queryset.values('is_private')
        owner = queryset.filter(owner__exact=self.request.user)
        if not self.request.user.is_superuser:
            if is_private and not owner:
                return Response(data=[])
            elif is_private and owner:
                projects = queryset.filter(groups__in=self.request.user.groups.all())
        else:
            projects = super().get_queryset()

        projects = self.filter_queryset(projects)
        serializer = self.get_serializer(projects, many=True)
        result_set = serializer.data
        return Response(result_set)

serializers.py序列化程序.py

class ProjectLightSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()
    slug = serializers.CharField()
    description = serializers.CharField()
    groups = GroupSerializer(many=True)
    created_date = serializers.DateTimeField()
    modified_date = serializers.DateTimeField()
    owner = UserSerializer()
    is_private = serializers.BooleanField()

models.py模型.py

class Project(models.Model):
    name = models.CharField(max_length=60, help_text=_("Name of project"))
    slug = models.SlugField(default="")
    groups = models.ManyToManyField(Group, help_text=_("Attached workgroup"))
    description = models.TextField(null=False, blank=False,
                                   verbose_name=_("description"))

    logo = models.FileField(upload_to=get_project_logo_file_path,
                            max_length=500, null=True, blank=True,
                            verbose_name=_("logo"))

    created_date = models.DateTimeField(null=False, blank=False, verbose_name=_("created date"), auto_now_add=True)
    modified_date = models.DateTimeField(null=False, blank=False, auto_now_add=True, verbose_name=_("modified date"))
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True,
                              related_name="owned_projects", verbose_name=_("owner"), on_delete=models.CASCADE)
    is_private = models.BooleanField(default=True, null=False, blank=True,
                                     verbose_name=_("is private"))
    tags = TaggableManager(help_text=_('A comma-separated list of tags.'), blank=True, through=TaggedItem,
                           to=Tag, verbose_name='Tags')

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)[:255]

            while type(self).objects.filter(slug=self.slug).exists():
                match_obj = re.match(r'^(.*)-(\d+)$', self.slug)
                if match_obj:
                    next_int = int(match_obj.group(2)) + 1
                    self.slug = match_obj.group(1) + "-" + str(next_int)
                else:
                    self.slug += '-2'

        super(Project, self).save(*args, **kwargs)

    def get_tags_display(self):
        return self.tags.values_list('name', flat=True)

    class Meta:
        db_table = 'projects'
        ordering = ["name", "id"]
        verbose_name = "Project"
        verbose_name_plural = "Projects"

Any assistance would be greatly appreciated.任何帮助将不胜感激。 Thanks in advance.提前致谢。

You can override the get_queryset method instead of list您可以覆盖get_queryset方法而不是list

from django.db.models import Q

class ProjectListViewSet(viewsets.ModelViewSet):
    serializer_class = ProjectLightSerializer
    authentication_classes = [TokenAuthentication, ]
    permission_classes = [unauthenticated, ]

    def get_queryset(self, request, *args, **kwargs):
        queryset = super().get_queryset(self, request, *args, **kwargs)
        is_private_query = Q(is_private=True, owner=self.request.user)
        groups_user_is_part_of = self.request.user.groups().values_list('id', flat=True)
        is_not_private_query = Q(is_private=False) & (Q(owner=self.request.user) | Q(groups__id__in=groups_user_is_part_of))

        return queryset.filter(is_private_query | is_not_private_query).order_by('name')

More here https://docs.djangoproject.com/en/3.0/topics/db/queries/#complex-lookups-with-q-objects更多在这里https://docs.djangoproject.com/en/3.0/topics/db/queries/#complex-lookups-with-q-objects

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM