Search code examples
pythondjangographqlgraphene-django

Django GraphQL returns null


I have a Django GraphQL app (graphene_django) running with djongo (mongoDB).

When I try to list all twitter queries (with GraphiQL), it returns null data :

My query :

query {
  allTwitterQueries {
    id,
    keyword
  }
}

Returns :

{
  "data": {
    "allTwitterQueries": null
  }
}

Here are my Django files :

untitled/schema.py

import untitled.api.schema
import graphene

from graphene_django.debug import DjangoDebug


class Query(
    untitled.api.schema.Query,
    graphene.ObjectType,
):
    debug = graphene.Field(DjangoDebug, name="_debug")


schema = graphene.Schema(query=Query)

untitled/api/models.py

from django.db import models
from django.contrib.auth.models import User


class TwitterQuery(models.Model):
    user_key = models.ForeignKey(User, related_name="created_by", on_delete=models.CASCADE, default=0)
    keyword = models.TextField(default="null")
    active = models.BooleanField(null=True)
    created_at = models.BigIntegerField(default=0)
    updated_at = models.BigIntegerField(default=0)
    count = models.IntegerField(default=0)

    def __str__(self):
        return self.keyword

untitled/api/schema.py

import graphene
from graphene_django.types import DjangoObjectType

from untitled.api.models import TwitterQuery


class TwitterQueryType(DjangoObjectType):
    class Meta:
        model = TwitterQuery


class Query(object):
    twitter_query = graphene.Field(TwitterQueryType, id=graphene.Int(), keyword=graphene.String(), active=graphene.Boolean())
    all_twitter_queries = graphene.List(TwitterQueryType)

    def fetch_twitter_queries(self, context):
        return TwitterQuery.objects.all()

    def fetch_twitter_query(self, context, user_id=None, active=None):
        if user_id is not None:
            return TwitterQuery.objects.get(user_id=user_id)
        if active is not None:
            return TwitterQuery.objects.get(active=active)

        return None

I have one item in my mongoDB instance :

{"_id":{"$oid":"5df20401d4e39b1e89223b15"},
"id":{"$numberInt":"1"},
"user_key_id":{"$numberInt":"1"},
"keyword":"greve",
"active":true,
"created_at":{"$numberLong":"1575846000000"},
"updated_at":{"$numberLong":"1575846000000"},
"count":{"$numberInt":"0"}}

Solution

  • At first sight I would assume that you would need to rename your resolves functions. Graphene uses a pattern where it looks for resole_x() where 'x' is the name of your field in the schema (https://docs.graphene-python.org/en/latest/types/objecttypes/#resolvers). Alternatively you can also pass resolver=your_function to the graphene.Field() where your_function can be any function.

    Graphene also provides a default resolver which tries to access the property from the parent if it's an object or dictionary. Since this is not the case for you (we are in the root of your query) you get null back because nothing is resolved.

    I think adjusting your code to this

    class Query(object): 
       twitter_query = graphene.Field(TwitterQueryType, id=graphene.Int(), keyword=graphene.String(), active=graphene.Boolean()) 
       all_twitter_queries = graphene.List(TwitterQueryType) 
    
       def resolve_all_twitter_queries(self, context): 
          return TwitterQuery.objects.all() 
    
       def resolve_twitter_query(self, context, user_id=None, active=None): 
           if user_id is not None: 
              return TwitterQuery.objects.get(user_id=user_id) 
           if active is not None: 
              return TwitterQuery.objects.get(active=active)
           return None
    

    Should do the trick.

    You should have another look in the documentation. It improved quiet a bit even though it is still not perfect :). Hope that helps you.