Decorators¶
Grapple exposes a few fields for the root schema such as pages
, images
, documents
, media
and redirects
.
Here are some useful decorators that allow you to expand your GraphQL schema further:
@register_query_field
¶
- class grapple.helpers.register_query_field(field_name, plural_field_name=None, query_params=None, required=False, plural_required=False, plural_item_required=False, middleware=None)¶
You can easily expose any Django model from your codebase by adding the @register_query_field
decorator like so:
from django.db import models
from wagtail.admin.edit_handlers import FieldPanel
from grapple.helpers import register_query_field
from grapple.models import GraphQLString
@register_query_field("advert")
class Advert(models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [FieldPanel("url"), FieldPanel("text")]
graphql_fields = [GraphQLString("url"), GraphQLString("text")]
def __str__(self):
return self.text
You can now query your adverts with the following query:
query {
# Get all adverts
adverts {
url
text
}
# Get a specific advert
advert(id: 1) {
url
text
}
}
You can add custom query parameters like so:
@register_query_field(
"advert", "adverts", {"id": graphene.Int(), "url": graphene.String()}
)
class Advert(models.Model):
pass # your actual implementation here
and then use it in your queries:
query {
# Get a specific advert
advert(url: "some-unique-url") {
url
text
}
}
You can make the singular query return type required like so:
@register_query_field("advert", required=True)
class Advert(models.Model):
pass # your actual implementation here
and then should look like this on your schema:
advert(id: Int): Advert!
instead of:
advert(id: Int): Advert
You can can also make the plural query return list type required:
@register_query_field("advert", plural_required=True)
class Advert(models.Model):
pass # your actual implementation here
making the plural query look like this on your schema:
adverts(id: Int, ...): [Advert]!
instead of the default:
adverts(id: Int, ...): [Advert]
If you want to make the plural query return list item type required:
@register_query_field("advert", plural_item_required=True)
class Advert(models.Model):
pass # your actual implementation here
making the plural query look like this:
adverts(id: Int, ...): [Advert!]
instead of the default:
adverts(id: Int, ...): [Advert]
You can add a middleware to the queries generated by the register_query_field
decorator:
from grapple.middleware import IsAuthenticatedMiddleware
@register_query_field("advert", middleware=[IsAuthenticatedMiddleware])
class Advert(models.Model):
pass # your actual implementation here
Note that you must add GrappleMiddleware
to the Graphene MIDDLEWARE
setting.
More information can be found in the middleware docs.
@register_paginated_query_field
¶
- class grapple.helpers.register_paginated_query_field(field_name, plural_field_name=None, query_params=None, required=False, plural_required=False, plural_item_required=False, middleware=None)¶
You can easily expose any Django model from your codebase by adding the @register_paginated_query_field
decorator like so:
from grapple.helpers import register_paginated_query_field
@register_paginated_query_field("advert")
class Advert(models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [FieldPanel("url"), FieldPanel("text")]
graphql_fields = [GraphQLString("url"), GraphQLString("text")]
def __str__(self):
return self.text
You can now query your adverts with the following query:
query {
# Get adverts paginated
adverts(page: 1, perPage: 10) {
items {
url
text
}
pagination {
total
count
perPage
currentPage
prevPage
nextPage
totalPages
}
}
# Get a specific advert
advert(id: 1) {
url
text
}
}
The default per_page
value is 10 and can be changed with the GRAPPLE["PAGE_SIZE"]
setting.
The per_page
has a maximum value of 100 by default and can be changed with the GRAPPLE["MAX_PAGE_SIZE"]
setting.
# settings.py
GRAPPLE = {
# ...
"PAGE_SIZE": 10,
"MAX_PAGE_SIZE": 100,
}
You can add custom query parameters like so:
@register_paginated_query_field(
"advert",
"adverts",
{
"id": graphene.Int(),
"url": graphene.String(),
},
)
class Advert(models.Model):
pass # your actual implementation here
and then use it in your queries:
query {
# Get a specific advert
advert(url: "some-unique-url") {
url
text
}
}
You can make the singular query return type required like so:
@register_paginated_query_field("advert", required=True)
class Advert(models.Model):
pass # your actual implementation here
and then should look like this on your schema:
advert(id: Int): Advert!
instead of:
advert(id: Int): Advert
You can can also make the plural query return list type required:
@register_paginated_query_field("advert", plural_required=True)
class Advert(models.Model):
pass # your actual implementation here
making the plural query look like this on your schema:
adverts(page: Int, perPage: Int, ...): AdvertPaginatedType!
Type AdvertPaginatedType {
items: [Advert]!
pagination: PaginationType!
}
instead of the default:
adverts(page: Int, perPage: Int, ...): AdvertPaginatedType
Type AdvertPaginatedType {
items: [Advert]
pagination: PaginationType
}
If you want to make the plural query return list item type required:
@register_paginated_query_field("advert", plural_item_required=True)
class Advert(models.Model):
pass # your actual implementation here
making the plural query look like this:
adverts(page: Int, perPage: Int, ...): AdvertPaginatedType
Type AdvertPaginatedType {
items: [Advert!]
pagination: PaginationType
}
instead of the default:
adverts(page: Int, perPage: Int, ...): AdvertPaginatedType
Type AdvertPaginatedType {
items: [Advert]
pagination: PaginationType
}
You can add middleware to the queries generated by the register_paginated_query_field
decorator:
from grapple.middleware import IsAuthenticatedMiddleware
@register_paginated_query_field("advert", middleware=[IsAuthenticatedMiddleware])
class Advert(models.Model):
pass # your actual implementation here
More information can be found on middleware docs.
@register_singular_query_field
¶
- class grapple.helpers.register_singular_query_field(field_name, query_params=None, required=False, middleware=None)¶
Returns the first item of the given type using the Model
ordering.
You can expose any Django model by decorating it with @register_singular_query_field
. This is especially useful
when you have Wagtail Pages with max_count
of one(Ref: Wagtail documentation),
thus there is no need to query by id.
from grapple.helpers import register_singular_query_field
@register_singular_query_field("first_advert")
class Advert(models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [FieldPanel("url"), FieldPanel("text")]
graphql_fields = [GraphQLString("url"), GraphQLString("text")]
def __str__(self):
return self.text
and then use it in your queries:
query {
# Get the first advert
firstAdvert {
url
text
}
}
If you have multiple items, you could change the order:
query {
# Get the first advert
firstAdvert(order: "-id") {
url
text
}
}
You can add middleware to the queries generated by the register_singular_query_field
decorator:
from grapple.middleware import IsAuthenticatedMiddleware
@register_singular_query_field("first_advert", middleware=[IsAuthenticatedMiddleware])
class Advert(models.Model):
pass # your actual implementation here
More information can be found on middleware docs.
@register_streamfield_block
¶
- class grapple.helpers.register_streamfield_block(cls)¶
The register_streamfield_block
decorator can be used to extend the schema with custom StreamField block types.
from wagtail import blocks
from grapple.helpers import register_streamfield_block
@register_streamfield_block
class CustomStreamBlock(blocks.StreamBlock):
text = blocks.TextBlock()
class Meta:
graphql_description = "This is a streamblock with a textblock child"
If a block’s Meta
class has a graphql_description
attribute, this value will be exposed as the description
in introspection queries.
To register additional interfaces for the block, add them with your block’s graphql_interfaces
attribute:
import graphene
from wagtail import blocks
from grapple.helpers import register_streamfield_block
class CustomInterface(graphene.Interface):
text = graphene.String()
@register_streamfield_block
class CustomInterfaceBlock(blocks.StructBlock):
text = blocks.TextBlock()
graphql_interfaces = (CustomInterface,)