Django Rest Framework 在 get_queryset 方法中过滤一个对象
Django Rest Framework Filtering an object in get_queryset method
基本上,我有一个目录视图集。在列表视图中,我想进行一些过滤并相应地 return 。
相关目录模型字段是:
class Catalog(models.Model):
name = models.CharField(max_length=191, null=True, blank=False)
...
team = models.ForeignKey(Team, on_delete=models.CASCADE, editable=False, related_name='catalogs')
whitelist_users = models.JSONField(null=True, blank=True, default=list) # If white list is null, it is open to whole team
Views.py
class CatalogViewSet(viewsets.ModelViewSet):
permission_classes = (IsOwnerAdminOrRestricted,)
def get_queryset(self):
result = []
user = self.request.user
catalogs = Catalog.objects.filter(team__in=self.request.user.team_set.all())
for catalog in catalogs:
if catalog.whitelist_users == [] or catalog.whitelist_users == None:
# catalog is open to whole team
result.append(catalog)
else:
# catalog is private
if user in catalog.whitelist_users:
result.append(catalog)
return result
这就是我的逻辑;
1 - 如果目录的团队是当前用户的团队之一,则获取目录对象。
2 - 检查 catalog.whitelist_users 是否包含当前用户。 (还有一个例外,如果它是 none 意味着它对整个团队开放,所以我可以在列表视图中显示它。)
现在这行得通了,但是由于我正在 return 创建一个数组,它没有正确找到详细信息对象。我的意思是 /catalog/ID 不能正常工作。
我是 DRF 的新手,所以我猜这里有问题。您将如何更好地实施此过滤?
想到的一个简单解决方案就是创建一个 PK 列表并再次过滤,这样您就可以 return 一个查询集。不是最有效的解决方案,但应该有效:
def get_queryset(self):
pks = []
user = self.request.user
catalogs = Catalog.objects.filter(team__in=user.team_set.all())
for catalog in catalogs:
if catalog.whitelist_users == [] or catalog.whitelist_users == None:
# catalog is open to whole team
pks.append(catalog.pk)
else:
# catalog is private
if user in catalog.whitelist_users:
pks.append(catalog.pk)
return Catalog.objects.filter(id__in=pks)
如方法名称所示,您需要 return 一个查询集。此外,如果没有必要,请避免迭代查询集。最好在一次数据库命中中完成。对于复杂查询,您可以使用 Q object.
from django.db.models import Q
# ...
def get_queryset(self):
user = self.request.user
catalogs = Catalog.objects.filter(
Q(whitelist_users__in=[None, []]) | Q(whitelist_users__contains=user),
team__in=user.team_set.all())
return catalogs
现在我不是 100% 确定 whitelist_users__contains=user
会起作用,因为它取决于您如何构建 JSON,但想法就在那里,您只需要调整它包含的内容。
这将比在 python 中循环更有效,并且会尊重 get_queryset
的含义。
基本上,我有一个目录视图集。在列表视图中,我想进行一些过滤并相应地 return 。 相关目录模型字段是:
class Catalog(models.Model):
name = models.CharField(max_length=191, null=True, blank=False)
...
team = models.ForeignKey(Team, on_delete=models.CASCADE, editable=False, related_name='catalogs')
whitelist_users = models.JSONField(null=True, blank=True, default=list) # If white list is null, it is open to whole team
Views.py
class CatalogViewSet(viewsets.ModelViewSet):
permission_classes = (IsOwnerAdminOrRestricted,)
def get_queryset(self):
result = []
user = self.request.user
catalogs = Catalog.objects.filter(team__in=self.request.user.team_set.all())
for catalog in catalogs:
if catalog.whitelist_users == [] or catalog.whitelist_users == None:
# catalog is open to whole team
result.append(catalog)
else:
# catalog is private
if user in catalog.whitelist_users:
result.append(catalog)
return result
这就是我的逻辑;
1 - 如果目录的团队是当前用户的团队之一,则获取目录对象。
2 - 检查 catalog.whitelist_users 是否包含当前用户。 (还有一个例外,如果它是 none 意味着它对整个团队开放,所以我可以在列表视图中显示它。)
现在这行得通了,但是由于我正在 return 创建一个数组,它没有正确找到详细信息对象。我的意思是 /catalog/ID 不能正常工作。
我是 DRF 的新手,所以我猜这里有问题。您将如何更好地实施此过滤?
想到的一个简单解决方案就是创建一个 PK 列表并再次过滤,这样您就可以 return 一个查询集。不是最有效的解决方案,但应该有效:
def get_queryset(self):
pks = []
user = self.request.user
catalogs = Catalog.objects.filter(team__in=user.team_set.all())
for catalog in catalogs:
if catalog.whitelist_users == [] or catalog.whitelist_users == None:
# catalog is open to whole team
pks.append(catalog.pk)
else:
# catalog is private
if user in catalog.whitelist_users:
pks.append(catalog.pk)
return Catalog.objects.filter(id__in=pks)
如方法名称所示,您需要 return 一个查询集。此外,如果没有必要,请避免迭代查询集。最好在一次数据库命中中完成。对于复杂查询,您可以使用 Q object.
from django.db.models import Q
# ...
def get_queryset(self):
user = self.request.user
catalogs = Catalog.objects.filter(
Q(whitelist_users__in=[None, []]) | Q(whitelist_users__contains=user),
team__in=user.team_set.all())
return catalogs
现在我不是 100% 确定 whitelist_users__contains=user
会起作用,因为它取决于您如何构建 JSON,但想法就在那里,您只需要调整它包含的内容。
这将比在 python 中循环更有效,并且会尊重 get_queryset
的含义。