[Solved]-How to use DRF serializers with Graphene

10πŸ‘

βœ…

I don’t see any reason why we have to do as shown in that tutorial. It is much easier to connect drf and graphql in following way. Doing this way,you do not need to worry about any vague classes and just rely on main aspects of drf and graphene.

Construct drf serializers normally, and connect it to graphql as shown below.

Consider we have model Subject. Let’s create CRUD api for it.

from graphene.types.scalars import Scalar

class ObjectField(Scalar): # to serialize error message from serializer
    @staticmethod
    def serialize(dt):
        return dt 


class SubjectType(DjangoObjectType):
    class Meta:
        model=Subject


# For mutation, use serializers

#creating subject
class CreateSubject(graphene.Mutation):
    subject=graphene.Field(SubjectType)
    message=ObjectField()
    status=graphene.Int()

    class Arguments:
        name=graphene.String(required=True)
        description=graphene.String(required=True)
   
    @classmethod
    def mutate(cls,root,info,**kwargs):
        serializer=SubjectSerializer(data=kwargs)
        if serializer.is_valid():
            obj=serializer.save()
            msg='success'
        else:
            msg=serializer.errors
            obj=None
            print(msg)
        return cls(subject=obj,message=msg,status=200)


'''Updating subject'''
class UpdateSubject(graphene.Mutation):
    subject=graphene.Field(SubjectType)
    status=graphene.Int()
    message=ObjectField()

    class Arguments:
        id=graphene.ID(required=True)
        name=graphene.String()
        description=graphene.String()

    @classmethod
    def mutate(cls,root,info,id,**kwargs):
        sub=Subject.objects.get(id=id)
        serializer=SubjectSerializer(sub,data=kwargs,partial=True)
        if serializer.is_valid():
            obj=serializer.save()
            msg='success'
        else:
            msg=serializer.errors
            obj=None
            print(msg)
        return cls(subject=obj,message=msg,status=200)


'''Delete Subject'''
class DeleteSubject(graphene.Mutation):
    message=ObjectField()
    status=graphene.Int()

    class Arguments:
        id=graphene.ID(required=True)

    @classmethod
    def mutate(cls,root,info,id,**kwargs):
        c=Subject.objects.get(id=id)
        c.delete()
        return cls(message='success',status=200)


class Mutation(graphene.ObjectType):
    create_subject=CreateSubject.Field()
    update_subject=UpdateSubject.Field()
    delete_subject=DeleteSubject.Field()

# Query is normal.

class Query(graphene.ObjectType):
    subject=graphene.Field(SubjectType,id=graphene.Int(), slug=graphene.String())
    
    subjects=graphene.List(SubjectType)

    def resolve_subject(self, info, id=None, slug=None):
        if id:
            return Subject.objects.get(id=id)
        if slug:
            return  Subject.objects.get(slug=slug)

    def resolve_subjects(self,info,**kwargs):
        return Subject.objects.all()

    

You can try making little framework-like thing for yourself to avoid redundant code as seen.

0πŸ‘

From your example:

import graphene
from your.schemas import Query as YourQuery
from your.serializers import ReservationComponentMutation

# notice its an objecttype, and i've also added some debug
class Mutation(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug, name="_debug")

    create_reservation = ReservationComponentMutation.Field()


class Query(YourQuery, graphene.ObjectType):
    pass


class Mutation(Mutation, graphene.ObjectType):
    pass


root_schema = graphene.Schema(query=Query, mutation=Mutation)

And the url:

urlpatterns = (
    url(r"^graphql", GraphQLView.as_view(schema=root_schema graphiql=True), name="graphql"),
)

# you can wrap csrf_exempt(GraphQLView.as_view(...)) for testing
# or you can setup the frontend `apollo-client` to use csrf_tokens
# also see the related links below

For example for apollo-client and not apollo-boost the window.csrf_token is {% csrf_token %} in the template rendering:

import { ApolloProvider } from "react-apollo";
import ApolloClient from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache as Cache } from "apollo-cache-inmemory";
import { ApolloLink } from "apollo-link";
import fetch from "unfetch";

const uri = UrlUtils.makeUrl(Urls.graphQl);
const AuthLink = (operation, next) => {
  const token = window.csrf_token; 

  operation.setContext(context => ({
    ...context,
    headers: {
      ...context.headers,
      "X-CSRFToken": token
    }
  }));

  return next(operation);
};

const link = ApolloLink.from([
  AuthLink,
  new HttpLink({
    uri,
    credentials: "same-origin",
    fetch // override fetch implementation for polyfills
  })
]);

const apollo = new ApolloClient({
  link,
  cache: new Cache().restore({})
});

You should then be able to:

query TestQuery() {
    resolveAllReservations () {
         id
    }
}

or:

mutate TestMutate($input: ReservationComponentMutationInput!) {
     createReservation(input: $input) {
         id
         errors {
           field
           messages
         }
     }
    _debug {
      sql {
        rawSql
      }
    }
}

related:

πŸ‘€jmunsch

Leave a comment