2

The default django User model have been extended using OneToOne link (some extra fields added to it).

Here is my model:

class Driver(models.Model):
    user = models.OneToOneField(
        User, 
        on_delete=models.CASCADE
    )
    father_name = models.CharField(
        max_length=20, 
        blank=True, 
        verbose_name="Father's Name"
    )
    national_id = models.CharField(
        max_length=10, 
        blank=True, 
        verbose_name="National ID"
    )
    phone_no = models.CharField(
        max_length=11,
        blank=True,
        verbose_name="Phone Number"
    )

and the following is my schema (if needed):

class DriverType(DjangoObjectType):
    class Meta:
        model = Driver

class Query(object):
    all_drivers = graphene.List(DriverType)

    def resolve_all_drivers(self, info, **kwargs):
        return Driver.objects.all()

Problem Definition: The default User of django (django.contrib.auth.model) has some fields like first_name, last_name, email, etc. According to the OneToOne relationship between User and Driver models, it is expected to access that data.

sample query:

query {
   allDrivers{
    id
    verified
    user {
      first_name
    }
  }
}

Error message:

"Cannot query field \"user\" on type \"DriverType\".",

Mostafa Ghadimi
  • 5,883
  • 8
  • 64
  • 102

2 Answers2

1

Here is how you can query data from a model that has an one ot one relation with the concerned model.

You need to make a DjangoObjectType of the model you are trying to reach and it will work.

Here is my models.py

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

class UserModel(models.Model):
    USER_TYPES = [
        ("CUSTOMER", "CUSTOMER"),
        ("AGENT", "AGENT"),
        ("ADMIN", "ADMIN"),
    ]
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    user_type = models.CharField(max_length=8, choices=USER_TYPES)

    def __str__(self):
        return f"P: {self.user.username}'s profile"

Here is my schema.py

from api.models import UserModel
from django.contrib.auth.models import User as auth_user
from graphene_django import DjangoObjectType
import graphene

class User(DjangoObjectType):
    class Meta:
        model = UserModel

class UserType(DjangoObjectType):
    class Meta:
        model = auth_user

class Query(graphene.ObjectType):
    hello = graphene.String(default_value="Hi!")
    user = graphene.Field(User, id=graphene.Int())

    def resolve_user(self, info, **kwargs):
        id = kwargs.get("id")
        if id is not None:
            return UserModel.objects.get(pk=id)
        return None

schema = graphene.Schema(query=Query)

Here is the query i ran in Graph*i*QL

query{
  user(id:3){
    id
    userType
    user{
      firstName
      lastName
      email
      username
      id
    }
    
  }
} 

The response I received

{
  "data": {
    "user": {
      "id": "3",
      "userType": "ADMIN",
      "user": {
        "firstName": "John",
        "lastName": "Doe",
        "email": "admin@site.com",
        "username": "admin001",
        "id": "1"
      }
    }
  }
}

Hope this was what you were looking for.

My reply is based on a reply to this issue.

https://github.com/graphql-python/graphene-django/issues/807#issuecomment-546310680

s13rw81
  • 142
  • 8
  • 1
    Yup, this is correct. Graphene seems to need to know the type exists even if you don't intend to access it directly. Thanks for this answer – David Lemayian Jun 13 '22 at 08:32
-1
class DriverType(DjangoObjectType):
    class Meta:
        model = Driver

class UserType(DjangoObjectType):
    class Meta:
        model = User

class Query(object):
    all_drivers = graphene.List(DriverType)
    all_users = graphene.List(UserType)

    def resolve_all_drivers(self, info, **kwargs):
        return Driver.objects.all()

    def resolve_all_users(self, info, **kwargs):
        return Users.objects.all()