【问题标题】:Django REST API query on related fieldDjango REST API 查询相关字段
【发布时间】:2020-02-20 15:35:15
【问题描述】:

我有 3 个模型,Run、RunParameter、RunValue:

class Run(models.Model):
    start_time = models.DateTimeField(db_index=True)
    end_time = models.DateTimeField()

class RunParameter(models.Model):
    parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)

class RunValue(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE)
    run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
    value = models.FloatField(default=0)

    class Meta:
            unique_together=(('run','run_parameter'),)

Run 可以有一个 RunValue,它是一个浮点值,其值的名称来自 RunParameter(基本上是一个包含名称),例如:

RunValue 可以是 AverageTimeMaximumTemperature

然后,Run 可以具有值为 X 的 RunValue = RunParameter:AverageTime

另一个 Run 实例可能有 RunValue = RunParameter:MaximumTemperature 值为 Y 等。

我创建了一个端点来查询我的 API,但我只有 RunParameter ID(因为您可以选择要绘制的参数的方式),而不是 RunValue强> ID直接。我基本上显示了所有 RunParameter 的列表和所有 Run 实例的列表,因为如果我显示 RunValue 的所有实例,列表也会冗长且令人困惑,因为您不会看到“最高温度”:

  • “运行 X 的最高温度”

  • “运行 Y 的最高温度”

  • “运行 Z 的最高温度”等(重复 50 次以上)。

我的 API 视图如下所示:

class RunValuesDetailAPIView(RetrieveAPIView):
    queryset = RunValue.objects.all()
    serializer_class = RunValuesDetailSerializer
    permission_classes = [IsOwnerOrReadOnly]]

序列化器看起来像这样:

class RunValuesDetailSerializer(ModelSerializer):
    run = SerializerMethodField()
    class Meta:
        model = RunValue
        fields = [
            'id',
            'run',
            'run_parameter',
            'value'
        ]
    def get_run(self, obj):
        return str(obj.run)

以及网址以防万一:

url(r'^run-values/(?P<pk>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),

由于我是 REST API 的新手,所以到目前为止,我只处理了我直接查询的模型 API 视图的 ID,但从未处理过相关字段的 ID。我不确定在哪里修改我的查询集以将 ID 传递给它以从相关字段中获取适当的模型实例。

在我进行 API 查询时,我有 Run 实例 ID 和 RunParameter ID。我需要查询集是:

run_value = RunValue.objects.get(run=run_id, run_parameter_id=param_id)

到目前为止,我只需要做类似的事情:

run_value = RunValue.objects.get(id=value_id) # I don't have this ID

【问题讨论】:

    标签: python django rest django-rest-framework django-queryset


    【解决方案1】:

    这很简单,您所要做的就是覆盖get_object 方法,例如(从documentation 复制粘贴):

    # view
    from django.shortcuts import get_object_or_404
    
    class RunValuesDetailAPIView(RetrieveAPIView):
        queryset = RunValue.objects.all()
        serializer_class = RunValuesDetailSerializer
        permission_classes = [IsOwnerOrReadOnly]]
        lookup_fields = ["run_id", "run_parameter_id"]
    
        def get_object(self):
            queryset = self.get_queryset()             # Get the base queryset
            queryset = self.filter_queryset(queryset)  # Apply any filter backends
            filter = {}
            for field in self.lookup_fields:
                if self.kwargs[field]: # Ignore empty fields.
                    filter[field] = self.kwargs[field]
            obj = get_object_or_404(queryset, **filter)  # Lookup the object
            self.check_object_permissions(self.request, obj)
            return obj
    
    # url
    url(r'^run-values/(?P<run_id>\d+)/(?P<run_parameter_id>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),
    

    但是您需要注意的一件大事是不要有相同的run_idrun_parameter_id 的重复条目,那么它会抛出错误。为避免这种情况,请使用unique_together=['run', 'run_parameter'],或者您可以在视图中使用queryset.filter(**filter).first() 而不是get_object_or_404。但是第二个选项在创建重复条目时会产生错误的结果。

    【讨论】:

    • 对象模型确实有一个独特的共同约束,我没有包括它以节省空间,但现在你提到它,它是相关的,我将编辑原始帖子以包括它们,以免混淆以后可能会找到答案的其他人。我会尝试这个解决方案并在这里更新。感谢您的帮助!
    • 您的回答有所帮助,但我该如何调整它以接受多个 RunParameter ID?假设我将我的 api 查询为:/api/run-values/?run=1&amp;run_parameter=29,30,31,32,33 ?
    • 可能您正在寻找过滤:django-rest-framework.org/api-guide/filtering
    【解决方案2】:

    如果我理解正确,您正在尝试获取一个只有Run id 和RunParameter id 的RunValue 实例,即基于相关字段的查询。

    查询集可以通过以下方式实现:

    run_value = RunValue.objects.get(
                              run__id=run_id,
                              run_parameter__id=run_parameter_id
                )
    

    假设 RunValue 实例只有 1 个相关的 RunRunParameter,这将返回您所追求的 RunValue 实例。

    如果这不是你的意思,请告诉我。

    双下划线允许您访问查询中的相关实例字段。

    【讨论】:

      猜你喜欢
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 2018-10-14
      • 1970-01-01
      • 2021-09-01
      • 2017-02-04
      • 1970-01-01
      • 2012-01-01
      相关资源
      最近更新 更多