如何进行可以找到 "latest" 或 "min" 或 "max" 的 graphql 查询

How to make graphql query that can find "latest" or "min" or "max"

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

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

我的models.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)

查询 return 一个时间跨度内的最低和最高温度,应该是这样的:

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

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

因为在 graphql 查询中使用了最小值和最大值,我不能只从解析器中 return 最小值和最大值,例如,如果查询是这样写的,

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)

models.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 查询中使用 'temperature' 而不是 'value'。现在可以使用了。

您可以使用 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

调用查询应该是一样的。