django - 如何通过 DRF 中相关模型中的字段过滤复杂数据库中的记录?
问题描述
我们希望能够通过相关表中的字段在所有表中找到记录。实际上,我们想搜索所有这些。
例如代码:
/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
有关系上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 有一堆明显的代码,如果有更多的表和表中的更多字段,就会有更多。我有多达 20 个表,并且这个相关链中的最后一个表可以过滤大约 40 个字段。因此,所有模型都可能有大约 400 条过滤规则,因此仅最后一个模型就有大约800行愚蠢的代码。一点都不好。
那么有什么正确的已知方法可以做到这一点吗?这个问题看起来很常见,所以也许有来自 Django 或它的任何库的嵌入式解决方案?
解决方案
最快的方法是更改传递给该视图的参数名称 GET['tourney_2'] 应该作为 GET['stage__tourney__tourney_2'] 可用。整个过滤将是:
queryset = self.get_queryset().filter(**request.GET)
当然,您应该检查参数名称以避免像 request.GET['deleted'] = True 这样的 SQL 注入
在实际项目中,您不能使用 **request.GET。您应该将其转换为普通的 Python dict filters = dict(request.GET) 并检查过滤器以防止 sql 注入攻击。
queryset = self.get_queryset().filter(**filters)
请查看如何动态构建查询。
推荐阅读
- flutter - bloc state is the same after coming back to a page even though it was explicitly changed
- javascript - 使用 Angular 检索 firebase 实时数据
- regex - 带有 javascript 排序的正则表达式
- pm2 - 如何强制 PM2 使用我的应用程序的最新版本?
- python - 如何使用 python selenium 单击图像中的这些按钮之一(通知)
- flutter - 未处理的异常:无效的参数:“TextEditingController”的实例
- azure-sql-database - Azure SQL 数据库中的备份用户
- python - 烧瓶 - python - 降价到 html
- c# - 如何在c#中的按钮单击事件中调用参数化方法
- reactjs - 打字稿中反应组件中道具的简洁易读语法