This package adds some extra functionalities to graphene-django to facilitate the graphql use without Relay:
NOTE: Subscription support was moved to graphene-django-subscriptions.
For installing graphene-django-extras, just run this command in your shell:
pip install graphene-django-extras
Fields:
DjangoObjectField
DjangoFilterListField
DjangoFilterPaginateListField
DjangoListObjectField (Recommended for Queries definition)
Mutations:
DjangoSerializerMutation (Recommended for Mutations definition)
Types:
DjangoListObjectType (Recommended for Types definition)
DjangoInputObjectType
DjangoSerializerType (Recommended for quick queries and mutations definitions)
Paginations:
LimitOffsetGraphqlPagination
PageGraphqlPagination
This is a basic example of graphene-django-extras package use. You can configure global params for DjangoListObjectType classes pagination definitions on settings.py like this:
GRAPHENE_DJANGO_EXTRAS = {
'DEFAULT_PAGINATION_CLASS': 'graphene_django_extras.paginations.LimitOffsetGraphqlPagination',
'DEFAULT_PAGE_SIZE': 20,
'MAX_PAGE_SIZE': 50,
'CACHE_ACTIVE': True,
'CACHE_TIMEOUT': 300 # seconds
}
from django.contrib.auth.models import User
from graphene_django_extras import DjangoListObjectType, DjangoSerializerType, DjangoObjectType
from graphene_django_extras.paginations import LimitOffsetGraphqlPagination
from .serializers import UserSerializer
class UserType(DjangoObjectType):
class Meta:
model = User
description = " Type definition for a single user "
filter_fields = {
"id": ("exact", ),
"first_name": ("icontains", "iexact"),
"last_name": ("icontains", "iexact"),
"username": ("icontains", "iexact"),
"email": ("icontains", "iexact"),
"is_staff": ("exact", ),
}
class UserListType(DjangoListObjectType):
class Meta:
description = " Type definition for user list "
model = User
pagination = LimitOffsetGraphqlPagination(default_limit=25, ordering="-username") # ordering can be: string, tuple or list
class UserModelType(DjangoSerializerType):
""" With this type definition it't necessary a mutation definition for user's model """
class Meta:
description = " User model type definition "
serializer_class = UserSerializer
pagination = LimitOffsetGraphqlPagination(default_limit=25, ordering="-username") # ordering can be: string, tuple or list
filter_fields = {
"id": ("exact", ),
"first_name": ("icontains", "iexact"),
"last_name": ("icontains", "iexact"),
"username": ("icontains", "iexact"),
"email": ("icontains", "iexact"),
"is_staff": ("exact", ),
}
from graphene_django_extras import DjangoInputObjectType
class UserInput(DjangoInputObjectType):
class Meta:
description = " User InputType definition to use as input on an Arguments class on traditional Mutations "
model = User
import graphene
from graphene_django_extras import DjangoSerializerMutation
from .serializers import UserSerializer
from .types import UserType
from .input_types import UserInputType
class UserSerializerMutation(DjangoSerializerMutation):
"""
DjangoSerializerMutation auto implement Create, Delete and Update functions
"""
class Meta:
description = " DRF serializer based Mutation for Users "
serializer_class = UserSerializer
class UserMutation(graphene.Mutation):
"""
On traditional mutation classes definition you must implement the mutate function
"""
user = graphene.Field(UserType, required=False)
class Arguments:
new_user = graphene.Argument(UserInput)
class Meta:
description = " Graphene traditional mutation for Users "
@classmethod
def mutate(cls, root, info, *args, **kwargs):
...
import graphene
from graphene_django_extras import DjangoObjectField, DjangoListObjectField, DjangoFilterPaginateListField,
DjangoFilterListField, LimitOffsetGraphqlPagination
from .types import UserType, UserListType, UserModelType
from .mutations import UserMutation, UserSerializerMutation
class Queries(graphene.ObjectType):
# Possible User list queries definitions
users = DjangoListObjectField(UserListType, description='All Users query')
users1 = DjangoFilterPaginateListField(UserType, pagination=LimitOffsetGraphqlPagination())
users2 = DjangoFilterListField(UserType)
users3 = DjangoListObjectField(UserListType, filterset_class=UserFilter, description='All Users query')
# Defining a query for a single user
# The DjangoObjectField have a ID type input field, that allow filter by id and is't necessary to define resolve function
user = DjangoObjectField(UserType, description='Single User query')
# Another way to define a query to single user
user1 = UserListType.RetrieveField(description='User List with pagination and filtering')
# Exist two ways to define single or list user queries with DjangoSerializerType
user_retrieve1, user_list1 = UserModelType.QueryFields(
description='Some description message for both queries',
deprecation_reason='Some deprecation message for both queries'
)
user_retrieve2 = UserModelType.RetrieveField(
description='Some description message for retrieve query',
deprecation_reason='Some deprecation message for retrieve query'
)
user_list2 = UserModelType.ListField(
description='Some description message for list query',
deprecation_reason='Some deprecation message for list query'
)
class Mutations(graphene.ObjectType):
user_create = UserSerializerMutation.CreateField(deprecation_reason='Some one deprecation message')
user_delete = UserSerializerMutation.DeleteField()
user_update = UserSerializerMutation.UpdateField()
# Exist two ways to define mutations with DjangoSerializerType
user_create1, user_delete1, user_update1 = UserModelType.MutationFields(
description='Some description message for create, delete and update mutations',
deprecation_reason='Some deprecation message for create, delete and update mutations'
)
user_create2 = UserModelType.CreateField(description='Description message for create')
user_delete2 = UserModelType.DeleteField(description='Description message for delete')
user_update2 = UserModelType.UpdateField(description='Description message for update')
traditional_user_mutation = UserMutation.Field()
For use Directives you must follow two simple steps:
# settings.py
GRAPHENE = {
'SCHEMA_INDENT': 4,
'MIDDLEWARE': [
'graphene_django_extras.ExtraGraphQLDirectiveMiddleware'
]
}
# schema.py
from graphene_django_extras import all_directives
schema = graphene.Schema(
query=RootQuery,
mutation=RootMutation,
directives=all_directives
)
NOTE: Date directive depends on dateutil module, so if you do not have installed it, this directive will not be available. You can install dateutil module manually:
pip install python-dateutil
or like this:
pip install graphene-django-extras[date]
That's all !!!
{
allUsers(username_Icontains:"john"){
results(limit:5, offset:5){
id
username
firstName
lastName
}
totalCount
}
allUsers1(lastName_Iexact:"Doe", limit:5, offset:0){
id
username
firstName
lastName
}
allUsers2(firstName_Icontains: "J"){
id
username
firstName
lastName
}
user(id:2){
id
username
firstName
}
user1(id:2){
id
username
firstName
}
}
mutation{
userCreate(newUser:{username:"test", password:"test*123"}){
user{
id
username
firstName
lastName
}
ok
errors{
field
messages
}
}
userDelete(id:1){
ok
errors{
field
messages
}
}
userUpdate(newUser:{id:1, username:"John"}){
user{
id
username
}
ok
errors{
field
messages
}
}
}
Let's suppose that we have this query:
query{
allUsers{
result{
id
firstName
lastName
dateJoined
lastLogin
}
}
}
And return this data:
{
"data": {
"allUsers": {
"results": [
{
"id": "1",
"firstName": "JOHN",
"lastName": "",
"dateJoined": "2017-06-20 09:40:30",
"lastLogin": "2017-08-05 21:05:02"
},
{
"id": "2",
"firstName": "Golden",
"lastName": "GATE",
"dateJoined": "2017-01-02 20:36:45",
"lastLogin": "2017-06-20 10:15:31"
},
{
"id": "3",
"firstName": "Nike",
"lastName": "just do it!",
"dateJoined": "2017-08-30 16:05:20",
"lastLogin": "2017-12-05 09:23:09"
}
]
}
}
}
As we see, some data it's missing or just not have the format that we like it, so let's go to format the output data that we desired:
query{
allUsers{
result{
id
firstName @capitalize
lastName @default(to: "Doe") @title_case
dateJoined @date(format: "DD MMM YYYY HH:mm:SS")
lastLogin @date(format: "time ago")
}
}
}
And we get this output data:
{
"data": {
"allUsers": {
"results": [
{
"id": "1",
"firstName": "John",
"lastName": "Doe",
"dateJoined": "20 Jun 2017 09:40:30",
"lastLogin": "4 months, 12 days, 15 hours, 27 minutes and 58 seconds ago"
},
{
"id": "2",
"firstName": "Golden",
"lastName": "Gate",
"dateJoined": "02 Jan 2017 20:36:45",
"lastLogin": "5 months, 28 days, 2 hours, 17 minutes and 53 seconds ago"
},
{
"id": "3",
"firstName": "Nike",
"lastName": "Just Do It!",
"dateJoined": "30 Aug 2017 16:05:20",
"lastLogin": "13 days, 3 hours, 10 minutes and 31 seconds ago"
}
]
}
}
}
As we see, the directives are an easy way to format output data on queries, and it's can be put together like a chain.
List of possible date's tokens: "YYYY", "YY", "WW", "W", "DD", "DDDD", "d", "ddd", "dddd", "MM", "MMM", "MMMM", "HH", "hh", "mm", "ss", "A", "ZZ", "z".
You can use this shortcuts too: