Reputation: 1002
I'm trying to use graphql with python to retrieve min and max temperatures within a time range.
The temperature table has 2 columns: timestamp and value.
My models.py is:
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}"
and schema.py is:
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)
The query that returns the min and max temperatures over a timespan, should be like this:
query {
temperatureStatistics(after: "2020-12-06T12:00:00+00:00", before: "2020-12-07T12:00:00+00:00") {
min
max
}
}
I cannot figure out how to implement the min and max parts of this.
Since the min and max are used in the graphql query I cannot just return min and max from a resolver, for example if the query were written like this,
query {
temperatureMax(after: "2020-12-06T12:00:00+00:00", before: "2020-12-07T12:00:00+00:00")
}
I have to somehow figure out how to enable graphql to do that work.
In response to @Ahtisham 's comment. Here is how I implemented currentTemperature without Types.
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()
This worked when queried with this graphql query:
query {
currentTemperature {
timestamp
value
}
}
UPDATE 2
I have updated my schema.py according to @Ahtisham 's answer and now have this as my 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 gives me this error
{
"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
}
]
}
]
}
when executing this query
query {
temperatureStatistics {
min
max
}
}
UPDATE 3
After changing
temperature_statistics = graphene.Field(Temperature, before=graphene.String(), after=graphene.String())
to
temperature_statistics = graphene.Field(RangeType, before=graphene.String(), after=graphene.String())
Graphql now gives me this error
{
"errors": [
{
"message": "Cannot resolve keyword 'temperature' into field. Choices are: id, timestamp, value",
"locations": [
{
"line": 2,
"column": 5
}
],
"path": [
"temperatureStatistics"
]
}
],
"data": {
"temperatureStatistics": null
}
}
when executing this query
query {
temperatureStatistics {
min
max
}
}
Also:
Graphql gives me this error
{
"errors": [
{
"message": "Cannot resolve keyword 'created_at' into field. Choices are: id, timestamp, value",
"locations": [
{
"line": 2,
"column": 5
}
],
"path": [
"temperatureStatistics"
]
}
],
"data": {
"temperatureStatistics": null
}
}
when executing this query
query {
temperatureStatistics(after: "2020-12-06T12:00:00+00:00", before: "2020-12-07T12:00:00+00:00")) {
min
max
}
}
UPDATE 4
The last error was because I was using 'temperature' instead of 'value' in my django query. It works now.
Upvotes: 1
Views: 2031
Reputation: 10126
You can define a new Type with min and max then add it to your Query like this:
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
Calling the query should be the same.
Upvotes: 1