如何通过DRF中相关模型中的字段过滤复杂数据库中的记录?
How to filter records in complex DB by the fields in related models in DRF?
我们希望能够通过相关 table 中的字段在所有 table 中找到记录。其实我们想搜索所有这些。
例如代码:
/models.py
class Tourney(models.Model):
tourney = models.CharField()
tourney_1 = models.CharField()
tourney_2 = models.CharField()
class Stage(models.Model):
tourney = models.ForeignKey(Tourney, on_delete=models.CASCADE)
stage = models.CharField()
stage_1 = models.CharField()
stage_2 = models.CharField()
class Group(models.Model):
stage = models.ForeignKey(Stage, on_delete=models.CASCADE)
group = models.CharField()
group_1 = models.CharField()
group_2 = models.CharField()
Group
与 Stage
有关系,Stage
与 Tourney
.
有关系
所以现在我们要为他们设置API。想象一下,我们为他们提供了简单的序列化程序,其中包括他们所有的字段,并称为 TourneySerializer
、StageSerializer
和 GroupSerializer
.
现在让我们尝试过滤 Group
模型。
/views.py
class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = serializers.GroupSerializer
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
if 'tourney' in request.GET:
queryset = queryset.filter(stage__tourney__tourney=request.GET['tourney'])
if 'tourney_1' in request.GET:
queryset = queryset.filter(stage__tourney__tourney_1=request.GET['tourney_1'])
if 'tourney_2' in request.GET:
queryset = queryset.filter(stage__tourney__tourney_2=request.GET['tourney_2'])
if 'stage' in request.GET:
queryset = queryset.filter(stage__stage=request.GET['stage'])
if 'stage_1' in request.GET:
queryset = queryset.filter(stage__stage_1=request.GET['stage_1'])
if 'stage_2' in request.GET:
queryset = queryset.filter(stage__stage_2=request.GET['stage_2'])
if 'group' in request.GET:
queryset = queryset.filter(group=request.GET['group'])
if 'group_1' in request.GET:
queryset = queryset.filter(group_1=request.GET['group_1'])
if 'group_2' in request.GET:
queryset = queryset.filter(group_2=request.GET['group_2'])
serializer = self.get_serializer_class()(
queryset,
many=True)
return Response(serializer.data)
这里我们有一个带有一堆明显代码的 ViewSet,如果 tables 和 tables 中的字段更多,还会有更多。我最多有 20 个 table,并且此相关链中的最后一个 table 可以过滤大约 40 个字段。因此,可能在所有模型上都有大约 400 条过滤规则,因此仅针对最后一个模型,大约有 800 行愚蠢的代码。一点都不好
那么有什么正确的已知方法可以做到这一点吗?这个问题看起来很常见,所以也许有来自 Django 或它的任何库的嵌入式解决方案?
最快的方法是更改您传递给该视图的参数名称 GET['tourney_2'] 应该可以作为 GET['stage__tourney__tourney_2'] 使用。
整个过滤将是:
queryset = self.get_queryset().filter(**request.GET)
当然你应该检查参数名称以避免 SQL 像 request.GET['deleted'] = True
这样的注入
在实际项目中不能使用**request.GET。您应该将其转换为正常的 Python dict filters = dict(request.GET) 并检查过滤器是否受到 sql 注入攻击。
queryset = self.get_queryset().filter(**filters)
请查看如何动态构建查询。
How to dynamically provide lookup field name in Django query?
我们希望能够通过相关 table 中的字段在所有 table 中找到记录。其实我们想搜索所有这些。
例如代码:
/models.py
class Tourney(models.Model):
tourney = models.CharField()
tourney_1 = models.CharField()
tourney_2 = models.CharField()
class Stage(models.Model):
tourney = models.ForeignKey(Tourney, on_delete=models.CASCADE)
stage = models.CharField()
stage_1 = models.CharField()
stage_2 = models.CharField()
class Group(models.Model):
stage = models.ForeignKey(Stage, on_delete=models.CASCADE)
group = models.CharField()
group_1 = models.CharField()
group_2 = models.CharField()
Group
与 Stage
有关系,Stage
与 Tourney
.
所以现在我们要为他们设置API。想象一下,我们为他们提供了简单的序列化程序,其中包括他们所有的字段,并称为 TourneySerializer
、StageSerializer
和 GroupSerializer
.
现在让我们尝试过滤 Group
模型。
/views.py
class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = serializers.GroupSerializer
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
if 'tourney' in request.GET:
queryset = queryset.filter(stage__tourney__tourney=request.GET['tourney'])
if 'tourney_1' in request.GET:
queryset = queryset.filter(stage__tourney__tourney_1=request.GET['tourney_1'])
if 'tourney_2' in request.GET:
queryset = queryset.filter(stage__tourney__tourney_2=request.GET['tourney_2'])
if 'stage' in request.GET:
queryset = queryset.filter(stage__stage=request.GET['stage'])
if 'stage_1' in request.GET:
queryset = queryset.filter(stage__stage_1=request.GET['stage_1'])
if 'stage_2' in request.GET:
queryset = queryset.filter(stage__stage_2=request.GET['stage_2'])
if 'group' in request.GET:
queryset = queryset.filter(group=request.GET['group'])
if 'group_1' in request.GET:
queryset = queryset.filter(group_1=request.GET['group_1'])
if 'group_2' in request.GET:
queryset = queryset.filter(group_2=request.GET['group_2'])
serializer = self.get_serializer_class()(
queryset,
many=True)
return Response(serializer.data)
这里我们有一个带有一堆明显代码的 ViewSet,如果 tables 和 tables 中的字段更多,还会有更多。我最多有 20 个 table,并且此相关链中的最后一个 table 可以过滤大约 40 个字段。因此,可能在所有模型上都有大约 400 条过滤规则,因此仅针对最后一个模型,大约有 800 行愚蠢的代码。一点都不好
那么有什么正确的已知方法可以做到这一点吗?这个问题看起来很常见,所以也许有来自 Django 或它的任何库的嵌入式解决方案?
最快的方法是更改您传递给该视图的参数名称 GET['tourney_2'] 应该可以作为 GET['stage__tourney__tourney_2'] 使用。 整个过滤将是:
queryset = self.get_queryset().filter(**request.GET)
当然你应该检查参数名称以避免 SQL 像 request.GET['deleted'] = True
这样的注入在实际项目中不能使用**request.GET。您应该将其转换为正常的 Python dict filters = dict(request.GET) 并检查过滤器是否受到 sql 注入攻击。
queryset = self.get_queryset().filter(**filters)
请查看如何动态构建查询。
How to dynamically provide lookup field name in Django query?