# Graphene-Django: building a GraphQL API on top of Django models

> Graphene-Django maps Django models and permissions onto a GraphQL schema. It suits Django teams that want typed, filterable queries without hand-writing a resolver layer, and it assumes you already know Django.

**graphql-python/graphene-django** — Build powerful, efficient, and flexible GraphQL APIs with seamless Django integration.

- Repository: https://github.com/graphql-python/graphene-django
- Website: http://docs.graphene-python.org/projects/django/en/latest/
- Stars: 4,395 · Forks: 761
- Language: Python
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/graphql-python-graphene-django

## The problem Graphene-Django removes: resolvers that mirror your models

A GraphQL server needs a type for every object it exposes and a resolver for every field. In a Django project those types usually mirror models one to one, and the resolvers are thin wrappers around the ORM. Writing that layer by hand is repetitive, and it drifts: rename a model field and the schema keeps serving the old name until something breaks in production.

Graphene-Django exists to collapse that layer. The README describes it as an open-source library that provides integration between Django and Graphene, a library for building GraphQL APIs, and lists automatic generation of the GraphQL schema and integration with Django's authentication and permission system among its features. The intended reader is a developer who already has models, views and settings, and wants a GraphQL endpoint next to them rather than a second service.

That framing sets the boundary. This is not a standalone GraphQL server and not a schema-first toolkit. It is an adapter, and its value is proportional to how much of your domain already lives in Django models.

## How a DjangoObjectType becomes a queryable field

The mechanism is a type class. You subclass DjangoObjectType and point its Meta at a model. Graphene-Django reads the model's fields and builds the corresponding GraphQL fields from them, so the schema follows the model rather than a hand-written definition. A Query class then exposes a field whose type is that object type, and a resolve_ method on the Query class returns the queryset.

The return value is the part worth pausing on. The README's example returns MyModel.objects.all(), which means the resolver hands back a lazy Django queryset and Graphene-Django resolves the requested fields from it. What the client asks for shapes how much of the queryset is actually consumed. This is where the widely repeated advice about query optimization applies: a query that walks a foreign key for every row in a list turns into one query per row unless you control the queryset yourself. The README does not document a query optimizer, and the related searches around 'graphene django optimizer' point at a separate package rather than anything in this repository.

Pagination and filtering are listed as features, and the repository ships a django-filter entry in its test requirements, so filtering is a supported path rather than an afterthought. The documentation, not this article, is where the exact filter argument names live.

## Installing Graphene-Django and serving a first query

Installation is a single pip command, per the README. Nothing in the repository suggests a build step or a code generator.

```bash
pip install graphene-django
```

After that, the app goes into INSTALLED_APPS and the schema path goes into a GRAPHENE dictionary in settings. The README shows both keys; the SCHEMA value is a dotted path to a schema object, so a typo there surfaces as an import error when Django starts.

```python
INSTALLED_APPS = [
    # ...
    'graphene_django',
]

GRAPHENE = {
    'SCHEMA': 'myapp.schema.schema'
}
```

The schema itself is a schema.py in your app. The README's example defines a DjangoObjectType bound to MyModel, a Query with a list field, and a resolve_mymodels method returning the full queryset. The final line builds a graphene.Schema from the Query class.

```python
import graphene
from graphene_django import DjangoObjectType
from .models import MyModel

class MyModelType(DjangoObjectType):
    class Meta:
        model = MyModel

class Query(graphene.ObjectType):
    mymodels = graphene.List(MyModelType)

    def resolve_mymodels(self, info, **kwargs):
        return MyModel.objects.all()

schema = graphene.Schema(query=Query)
```

To reach it over HTTP, the README mounts GraphQLView in urls.py and passes graphiql=True, which serves the in-browser IDE. The comment in that snippet is explicit that the schema path is the one defined in GRAPHENE['SCHEMA'], so the view does not take the schema as an argument.

```python
from django.urls import path
from graphene_django.views import GraphQLView
from . import schema

urlpatterns = [
    # ...
    path('graphql/', GraphQLView.as_view(graphiql=True)),
]
```

With the server running, a POST to /graphql/ carrying a query for mymodels should return the fields you selected. If it returns an error about the schema instead, the dotted path in settings is the first thing to check.

## Testing a Graphene-Django endpoint with GraphQLTestCase

The README documents a test base class rather than leaving you to build requests by hand. GraphQLTestCase takes the schema through a GRAPHENE_SCHEMA attribute, and self.query() sends a GraphQL document through Django's test client.

```python
from django.test import TestCase
from graphene_django.utils.testing import GraphQLTestCase
from . import schema

class MyModelAPITestCase(GraphQLTestCase):
    GRAPHENE_SCHEMA = schema.schema

    def test_query_all_mymodels(self):
        response = self.query(
            '''
            query {
                mymodels {
                    id
                    name
                }
            }
            '''
        )

        self.assertResponseNoErrors(response)
        self.assertEqual(len(response.data['mymodels']), MyModel.objects.count())
```

The two assertions do different jobs. assertResponseNoErrors checks the GraphQL response envelope, which is where resolver exceptions land, and the equality check compares the returned list against the model count. Note the import of TestCase in the README snippet; GraphQLTestCase is the class actually used, and the extra import is unused in that example.

## Where Graphene-Django is the wrong tool

The README's own feature list stops short of real-time. Subscriptions are not among the listed features; the related projects section points at Graphene-Subscriptions as a separate package for adding them. If your API is primarily a live feed, you are assembling that from parts this repository does not supply.

The second limit is the coupling itself. Automatic schema generation from models is convenient until the public contract needs to differ from the internal model. Renaming a model field for a database reason changes the schema your clients depend on unless you override the field explicitly. Teams that treat the GraphQL schema as a versioned public API, with deprecation cycles and a schema registry, get less from the automatic path than teams whose clients are their own frontend.

A third case is a project without Django models at all. If the data lives behind an existing REST service or a non-relational store, the DjangoObjectType machinery has nothing to bind to, and Graphene without the Django integration is the smaller dependency. The repository's own related projects list Graphene-SQLAlchemy for the equivalent job on SQLAlchemy, which is the honest signal that the Django integration is one adapter among several.

## Graphene versus Graphene-Django versus a schema-first server

The closest alternative in the same family is Graphene itself. It builds GraphQL APIs in Python and has no knowledge of Django models, settings or permissions. Choosing it means writing your own object types and resolvers, and wiring authentication yourself. The trade is control: you decide exactly what each field returns, and nothing changes underneath you when a model changes.

The other direction is a schema-first server where the schema is the source of truth and resolvers are attached to it. Graphene-Django works the other way around, deriving the schema from Python classes. Neither approach is strictly better; the difference shows up in review. In a schema-first project, a schema diff is the artifact a reviewer reads. In Graphene-Django, the schema is an output, and you inspect it by running the server or exporting it. For a team whose backend and frontend are the same repository, deriving the schema is less work. For a team publishing an API to outside consumers, the derived schema is a build artifact you have to check, not a document you edit.

## Maintenance, upgrades and the MIT licence

The repository is not archived, and the last push was on 2026-06-24. The most recent release listed is v3.2.3 from 2025-03-13, following v3.2.2 in June 2024 and v3.2.1 in April 2024. Release cadence is therefore uneven, and a user should read the releases page rather than assume a schedule.

Version support is declared in setup.py classifiers. The package lists Python 3.8 through 3.12, including PyPy, and Django 3.2, 4.1, 4.2, 5.1 and 5.2. That list is the concrete thing to check before upgrading Django: a Django release that is not in the classifiers is untested by the maintainers, whatever the changelog says. The classifiers also mark the project as Production/Stable.

Upgrade cost concentrates in two places. First, Graphene itself is a dependency with its own release cycle, so a Graphene major version can force changes in your type definitions even when Graphene-Django has not moved. Second, the automatic field generation means a Django upgrade that changes model metadata can change the schema. Neither is documented as a migration procedure in the README.

The licence is MIT, which permits commercial use and modification with the copyright notice retained. This is not legal advice; if you redistribute the library inside a product, have your own counsel read the LICENSE file rather than a summary.

## Conclusion

Adopt Graphene-Django if your data already lives in Django models and you want a GraphQL surface without maintaining a separate resolver layer; skip it if you need subscriptions or a schema-first workflow. Before committing, verify that your Django version appears in the setup.py classifiers and that the schema path in GRAPHENE['SCHEMA'] resolves at startup, because a wrong path fails at import time, not at query time.

## FAQ

### What is Graphene-Django?

It is a Python library that integrates Django with Graphene, the library for building GraphQL APIs, and generates a GraphQL schema from your Django models. It is distributed on PyPI and licensed under MIT.

### How do I install Graphene-Django?

Run pip install graphene-django, then add 'graphene_django' to INSTALLED_APPS and set GRAPHENE = {'SCHEMA': 'myapp.schema.schema'} in your settings. The README also shows mounting GraphQLView in urls.py to serve the endpoint.

### Does Graphene-Django support subscriptions?

Subscriptions are not listed among the README's features. The related projects section points to Graphene-Subscriptions as a separate package for adding real-time subscriptions to Graphene-based APIs.

### Which Django and Python versions does Graphene-Django support?

The setup.py classifiers list Python 3.8 through 3.12 including PyPy, and Django 3.2, 4.1, 4.2, 5.1 and 5.2. A Django version outside that list is not covered by the declared classifiers.

### How do I test a Graphene-Django API?

Subclass graphene_django.utils.testing.GraphQLTestCase, set GRAPHENE_SCHEMA to your schema object, and call self.query() with a GraphQL document. The README pairs assertResponseNoErrors with an assertion on response.data.

## Sources

- [graphql-python/graphene-django on GitHub](https://github.com/graphql-python/graphene-django)
- [License: MIT](https://github.com/graphql-python/graphene-django/blob/main/LICENSE)
- [Project website](http://docs.graphene-python.org/projects/django/en/latest/)
- [README](https://github.com/graphql-python/graphene-django/blob/main/README.md)
- [Releases](https://github.com/graphql-python/graphene-django/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/graphql-python-graphene-django
