graphene-django

repository·main·Indexed 26 days ago

https://github.com/graphql-python/graphene-django

Integration between Django and Graphene for building GraphQL APIs using Django models, authentication, and permissions. Features include DjangoObjectType for model mapping, GraphQLView for API exposure, and GraphQLTestCase for testing. It provides tools for authorization via get_queryset and resolvers, Relay-compliant pagination with DjangoConnectionField, and integration with django-filter for complex query filtering and ordering.

Tokens
19.2K
Snippets
61
Records
73
Agent score
88%

What's inside graphene-django

  1. Get started with Graphene-Django

    main

    Graphene-Django is an abstraction layer built on top of Graphene designed to simplify adding GraphQL functionality to Django projects.

    To begin using Graphene-Django, follow these steps:

    1. Follow the Installation guide to set up your environment.
    2. Complete the Basic Tutorial to understand the core workflow.
    3. Familiarize yourself with the core Graphene utilities (the base library) to understand basic GraphQL concepts.

    If your goal is to expose Django data through GraphQL, focus on the Installation, Schema, and Queries documentation sections.

  2. Expose related models in DjangoObjectType

    main

    To query related models (e.g., a ForeignKey), the related model must also be defined as a DjangoObjectType subclass. If the related model is not defined as a DjangoObjectType, the relation field will fail to appear in the schema.

    from graphene_django import DjangoObjectType
    from .models import Question, Category
    
    class CategoryType(DjangoObjectType):
        class Meta:
            model = Category
            fields = ("foo",)
    
    class QuestionType(DjangoObjectType):
        class Meta:
            model = Question
            fields = ("category",)
  3. Define Relay-compatible DjangoObjectType nodes

    main

    To use Relay features like global IDs and connections, define your DjangoObjectType classes with relay.Node in the interfaces option of the Meta class. You can also use filter_fields to enable advanced filtering via django-filter.

    from graphene import relay, ObjectType
    from graphene_django import DjangoObjectType
    from graphene_django.filter import DjangoFilterConnectionField
    from ingredients.models import Category, Ingredient
    
    class CategoryNode(DjangoObjectType):
        class Meta:
            model = Category
            fields = '__all__'
            filter_fields = ['name', 'ingredients']
            interfaces = (relay.Node, )
    
    class IngredientNode(DjangoObjectType):
        class Meta:
            model = Ingredient
            fields = '__all__'
            filter_fields = {
                'name': ['exact', 'icontains', 'istartswith'],
                'notes': ['exact', 'icontains'],
                'category': ['exact'],
                'category__name': ['exact'],
            }
            interfaces = (relay.Node, )
    
    class Query(ObjectType):
        category = relay.Node.Field(CategoryNode)
        all_categories = DjangoFilterConnectionField(CategoryNode)
    
        ingredient = relay.Node.Field(IngredientNode)
        all_ingredients = DjangoFilterConnectionField(IngredientNode)
  4. Configure graphene-django in Django settings

    main

    To use graphene-django, add graphene_django to your INSTALLED_APPS. If you want to use the GraphiQL API browser, you must also include django.contrib.staticfiles.

    Additionally, you must define the GRAPHENE configuration dictionary in settings.py to point to your project's Schema object location.

    # settings.py
    
    INSTALLED_APPS = [
        ...
        "django.contrib.staticfiles", # Required for GraphiQL
        "graphene_django"
    ]
    
    GRAPHENE = {
        "SCHEMA": "django_root.schema.schema"
    }
  5. Install Django and Graphene Django

    main

    To set up a new project with Graphene Django support, create a virtual environment and install the required packages using pip.

    # Create the project directory
    mkdir cookbook
    cd cookbook
    
    # Create a virtualenv to isolate our package dependencies locally
    virtualenv env
    source env/bin/activate  # On Windows use `env\Scripts\activate`
    
    # Install Django and Graphene with Django support
    pip install django graphene_django
  6. Filter querysets based on the authenticated user

    main

    When using GraphQLView, the Django request is available in info.context. You can use this to filter querysets based on the current user.

    If you are using a custom view instead of GraphQLView, ensure you pass the request into the schema execution using context_value=request.

    # Using info.context in a resolver
    class Query(ObjectType):
        my_posts = DjangoFilterConnectionField(PostNode)
    
        def resolve_my_posts(self, info):
            if not info.context.user.is_authenticated:
                return Post.objects.none()
            else:
                return Post.objects.filter(owner=info.context.user)
    
    # If using a custom view, pass the request manually
    result = schema.execute(query, context_value=request)
  7. Add fields to the schema using mixins

    main

    You can extend your Query and Mutation objects by using multiple inheritance (mixins). This allows you to register existing ObjectType definitions from different modules into a single central schema object.

    import graphene
    
    import my_app.schema.Query
    import my_app.schema.Mutation
    
    class Query(
        my_app.schema.Query, # Add your Query objects here
        graphene.ObjectType
    ):
        pass
    
    class Mutation(
        my_app.schema.Mutation, # Add your Mutation objects here
        graphene.ObjectType
    ):
        pass
    
    schema = graphene.Schema(query=Query, mutation=Mutation)
  8. Apply custom filtering to DjangoListField using get_queryset or resolvers

    main

    You can filter the results of a DjangoListField in two ways:

    1. Via get_queryset on the DjangoObjectType: Define a @classmethod get_queryset(cls, queryset, info) on your DjangoObjectType. This is useful for logic tied to the type itself.
    2. Via a field resolver on the Query type: Define a resolve_<field_name>(parent, info) method on your Query class. This allows for field-specific filtering logic.

    When resolving a DjangoListField, the get_queryset method will be called with either the return of the field resolver (if one is defined) or the default queryset from the Django model.

    from graphene import ObjectType, Schema
    from graphene_django import DjangoListField
    
    class RecipeType(DjangoObjectType):
       class Meta:
          model = Recipe
          fields = ("title", "instructions")
    
       @classmethod
       def get_queryset(cls, queryset, info):
          # Filter out recipes that have no title
          return queryset.exclude(title__exact="")
    
    class Query(ObjectType):
       recipes = DjangoListField(RecipeType)
    
       def resolve_recipes(parent, info):
          # Only get recipes that have been published
          return Recipe.objects.filter(published=True)
    
    schema = Schema(query=Query)
  9. Adopt Relay for Pagination and Abstract IDs

    main

    To enable Relay features like pagination, slicing, and abstract id values in Graphene-Django, you must implement relay.Node in your DjangoObjectType and define a relay.Connection.

    Key steps:

    1. Import relay from graphene.
    2. Add relay.Node to the interfaces tuple in the DjangoObjectType.Meta class.
    3. Define a Connection class inheriting from relay.Connection with the node set to your DjangoObjectType in its Meta class.
    4. Use relay.ConnectionField in your Query class to expose the connection.
    from graphene import relay
    from graphene_django import DjangoObjectType
    from .models import Question
    
    class QuestionType(DjangoObjectType):
        class Meta:
            model = Question
            interfaces = (relay.Node,)
            fields = "__all__"
    
    class QuestionConnection(relay.Connection):
        class Meta:
            node = QuestionType
    
    class Query:
        questions = relay.ConnectionField(QuestionConnection)
    
        def resolve_questions(root, info, **kwargs):
            return Question.objects.all()
  10. Create custom mutations in Graphene-Django

    main

    You can create custom mutations by inheriting from graphene.Mutation. Define input arguments in a class Arguments and specify the response fields as class attributes. The logic resides in the @classmethod mutate. Ensure you return an instance of the mutation class containing the response data.

    import graphene
    from graphene_django import DjangoObjectType
    from .models import Question
    
    class QuestionType(DjangoObjectType):
        class Meta:
            model = Question
            fields = '__all__'
    
    class QuestionMutation(graphene.Mutation):
        class Arguments:
            # The input arguments for this mutation
            text = graphene.String(required=True)
            id = graphene.ID()
    
        # The class attributes define the response of the mutation
        question = graphene.Field(QuestionType)
    
        @classmethod
        def mutate(cls, root, info, text, id):
            question = Question.objects.get(pk=id)
            question.text = text
            question.save()
            # Notice we return an instance of this mutation
            return QuestionMutation(question=question)
    
    class Mutation(graphene.ObjectType):
        update_question = QuestionMutation.Field()
  11. Implement GraphQL Subscriptions with graphene-django

    main

    The graphene-django project does not support GraphQL subscriptions out of the box. To implement websocket-based subscription support, follow these steps:

    1. Install and configure django-channels.
    2. Install a third-party subscription module. Recommended community options include:
      • graphql-python/graphql-ws
      • datavance/django-channels-graphql-ws
      • jaydenwindle/graphene-subscriptions
    3. Use an ASGI protocol server to serve your application (or GraphQL endpoint). Examples include daphne (built into django-channels), uvicorn, or hypercorn.