如何进行可以查找&Quot;最新&Quot;、最小&Quot;或&Quot;最大&Quot;的GraphQL查询

问题描述

我正在尝试结合使用GraphQL和python来检索时间范围内的最低和最高温度。

温度表有2列:时间戳和值。

我的mods.py是:

from django.db import models

class Temperature(models.Model):
    timestamp = models.DateTimeField(auto_now=True)
    value = models.FloatField()

    def __str__(self):
        return f"the value:time is {self.value}:{self.timestamp}"

,schema.py为:

class Query(graphene.ObjectType):
    temperature_statistics = graphene.Field(Temperature)

    def resolve_temperature_statistics(self, info, **kwargs):
        before = kwargs.get("before")
        after = kwargs.get("after")
    
        return models.Temperature.objects.filter(created_at__gte=after, created_at__lte=before)

返回一段时间内的最低和最高温度的查询应该如下所示:

query {
    temperatureStatistics(after: "2020-12-06T12:00:00+00:00", before: "2020-12-07T12:00:00+00:00") {
        min
        max
    }
}

我不知道如何实现其中的最小和最大部分。

由于在GraphQL查询中使用了min和max,因此我不能只从解析器返回min和max,例如,如果查询是这样编写的,

query {
    temperatureMax(after: "2020-12-06T12:00:00+00:00", before: "2020-12-07T12:00:00+00:00")
}

我必须想办法使GraphQL能够完成这项工作。

回应@Ahtisham的评论。以下是我如何实现不带类型的currentTemperature。

schema.py

import graphene
from graphene_django import DjangoObjectType

from temperature import models

class Temperature(DjangoObjectType):
    class Meta:
        model = models.Temperature

class Query(graphene.ObjectType):
    current_temperature = graphene.Field(Temperature)

    def resolve_current_temperature(self, info, **kwargs):
        return models.Temperature.objects.last()


schema = graphene.Schema(query=Query)

mods.py

from django.db import models

class Temperature(models.Model):
    timestamp = models.DateTimeField(auto_now=True)
    value = models.FloatField()

这在使用此GraphQL查询进行查询时起作用:

query {
    currentTemperature {
        timestamp
        value
    }
}

更新2

我已经根据@Ahtisham的回答更新了schema.py,现在将其作为我的schema.py:

import graphene
from graphene_django import DjangoObjectType
from django.db.models import Max, Min


from temperature import models

class Temperature(DjangoObjectType):
    class Meta:
        model = models.Temperature

class RangeType(graphene.ObjectType):
    min = graphene.String()
    max = graphene.String()

class Query(graphene.ObjectType):
    current_temperature = graphene.Field(Temperature, id=graphene.Int())
    temperature_statistics = graphene.Field(Temperature, before=graphene.String(), after=graphene.String())

    def resolve_current_temperature(self, info, **kwargs):
        return models.Temperature.objects.latest('timestamp')
        

    def resolve_temperature_statistics(self, info, before=None, after=None):
        range_type = RangeType()

        if before and after is not None:
            range_type.min_ = models.Temperature.objects.filter(created_at__gte=after, created_at__lte=before).aggregate(Min('temperature'))
            range_type.max_ = models.Temperature.objects.filter(created_at__gte=after, created_at__lte=before).aggregate(Max('temperature'))
            return range_type
            
        elif before is None and after is not None:
            range_type.min_ = models.Temperature.objects.filter(created_at__gte=after).aggregate(Min('temperature'))
            range_type.max_ = models.Temperature.objects.filter(created_at__gte=after).aggregate(Max('temperature'))
            return range_type

        elif after is None and before is not None:
            range_type.min_ = models.Temperature.objects.filter(created_at__lte=before).aggregate(Min('temperature'))
            range_type.max_ = models.Temperature.objects.filter(created_at__lte=before).aggregate(Max('temperature'))
            return range_type

        else:
            range_type.min_ = models.Temperature.objects.aggregate(Min('temperature'))
            range_type.max_ = models.Temperature.objects.aggregate(Max('temperature'))
            return range_type

    
schema = graphene.Schema(query=Query)

GraphQL显示此错误

{
  "errors": [
    {
      "message": "Cannot query field "min_" on type "Temperature".",
      "locations": [
        {
          "line": 3,
          "column": 7
        }
      ]
    },
    {
      "message": "Cannot query field "max_" on type "Temperature".",
      "locations": [
        {
          "line": 4,
          "column": 7
        }
      ]
    }
  ]
}

执行此查询时

query {
    temperatureStatistics {
                min
                max
        }
}

更新3

更改后

    temperature_statistics = graphene.Field(Temperature, before=graphene.String(), after=graphene.String())

    temperature_statistics = graphene.Field(RangeType, before=graphene.String(), after=graphene.String())

GraphQL现在显示此错误

{
  "errors": [
    {
      "message": "Cannot resolve keyword 'temperature' into field. Choices are: id, timestamp, value",
      "locations": [
        {
          "line": 2,
          "column": 5
        }
      ],
      "path": [
        "temperatureStatistics"
      ]
    }
  ],
  "data": {
    "temperatureStatistics": null
  }
}

执行此查询时

query {
    temperatureStatistics {
                min
                max
        }
}

同时:

GraphQL显示此错误

{
  "errors": [
    {
      "message": "Cannot resolve keyword 'created_at' into field. Choices are: id, timestamp, value",
      "locations": [
        {
          "line": 2,
          "column": 5
        }
      ],
      "path": [
        "temperatureStatistics"
      ]
    }
  ],
  "data": {
    "temperatureStatistics": null
  }
}

执行此查询时

query {
    temperatureStatistics(after: "2020-12-06T12:00:00+00:00", before: "2020-12-07T12:00:00+00:00")) {
                min
                max
        }
}

更新4

最后一个错误是因为我在Django查询中使用了‘温度’而不是‘值’。现在可以使用了。


解决方案

您可以使用MIN和MAX定义一个新类型,然后将其添加到查询中,如下所示:

class RangeType(graphene.ObjectType):
    min = graphene.String()
    max = graphene.String()
       

class Query(graphene.ObjectType):
    temperature_statistics = graphene.Field(
       RangeType, before=graphene.String(), after=graphene.String()
    )

    def resolve_temperature_statistics(self, info, before=None, after=None):
        range_type = RangeType()
        range_type.min = # query to get min value
        range_type.max = # query to get max value
        return range_type

调用查询应该相同。

相关文章