Authorization in Django¶
There are several ways you may want to limit access to data when working with Graphene and Django: limiting which fields are accessible via GraphQL and limiting which objects a user can access.
Let’s use a simple example model.
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
published = models.BooleanField(default=False)
owner = models.ForeignKey('auth.User')
Limiting Field Access¶
To limit fields in a GraphQL query simply use the only_fields
meta attribute.
from graphene import relay
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
model = Post
only_fields = ('title', 'content')
interfaces = (relay.Node, )
conversely you can use exclude_fields
meta attribute.
from graphene import relay
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
model = Post
exclude_fields = ('published', 'owner')
interfaces = (relay.Node, )
Queryset Filtering On Lists¶
In order to filter which objects are available in a queryset-based list, define a resolve method for that field and return the desired queryset.
from graphene import ObjectType
from graphene_django.filter import DjangoFilterConnectionField
from .models import Post
class Query(ObjectType):
all_posts = DjangoFilterConnectionField(PostNode)
def resolve_all_posts(self, info):
return Post.objects.filter(published=True)
User-based Queryset Filtering¶
If you are using GraphQLView
you can access Django’s request
with the context argument.
from graphene import ObjectType
from graphene_django.filter import DjangoFilterConnectionField
from .models import Post
class Query(ObjectType):
my_posts = DjangoFilterConnectionField(PostNode)
def resolve_my_posts(self, info):
# context will reference to the Django request
if not info.context.user.is_authenticated():
return Post.objects.none()
else:
return Post.objects.filter(owner=info.context.user)
If you’re using your own view, passing the request context into the schema is simple.
result = schema.execute(query, context_value=request)
Filtering ID-based Node Access¶
In order to add authorization to id-based node access, we need to add a
method to your DjangoObjectType
.
from graphene_django.types import DjangoObjectType
from .models import Post
class PostNode(DjangoObjectType):
class Meta:
model = Post
only_fields = ('title', 'content')
interfaces = (relay.Node, )
@classmethod
def get_node(cls, id, info):
try:
post = cls._meta.model.objects.get(id=id)
except cls._meta.model.DoesNotExist:
return None
if post.published or info.context.user == post.owner:
return post
return None
Adding Login Required¶
To restrict users from accessing the GraphQL API page the standard Django LoginRequiredMixin can be used to create your own standard Django Class Based View, which includes the LoginRequiredMixin
and subclasses the GraphQLView
.:
After this, you can use the new PrivateGraphQLView
in the project’s URL Configuration file url.py
:
For Django 1.9 and below:
urlpatterns = [
# some other urls
url(r'^graphql', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
]
For Django 2.0 and above:
urlpatterns = [
# some other urls
path('graphql', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
]