在 Django ModelViewSet 中过滤
Filtering in Django ModelViewSet
我觉得我做的不对。我想做的是防止数据不符合我的标准时被返回。以下是标准:
如果满足以下条件,用户应该能够看到该项目:
- 如果对象是私有的并且他们是所有者
-- 或--
- 该项目不是私有的
- 如果用户是所有者,或者他们是指定组的成员
根据评论编辑:
下面的代码似乎有效,但我仍然不确定这是正确的逻辑还是正确的方法。
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
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
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"
如有任何帮助,我们将不胜感激。提前致谢。
您可以覆盖 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')
这里有更多内容https://docs.djangoproject.com/en/3.0/topics/db/queries/#complex-lookups-with-q-objects
我觉得我做的不对。我想做的是防止数据不符合我的标准时被返回。以下是标准:
如果满足以下条件,用户应该能够看到该项目:
- 如果对象是私有的并且他们是所有者
-- 或--
- 该项目不是私有的
- 如果用户是所有者,或者他们是指定组的成员
根据评论编辑:
下面的代码似乎有效,但我仍然不确定这是正确的逻辑还是正确的方法。
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
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
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"
如有任何帮助,我们将不胜感激。提前致谢。
您可以覆盖 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')
这里有更多内容https://docs.djangoproject.com/en/3.0/topics/db/queries/#complex-lookups-with-q-objects