Fields¶
django-graphex provides several field types for building GraphQL schemas with enhanced functionality.
DjangoObjectField¶
Used for single object queries with automatic ID filtering.
from django_graphex import DjangoObjectField
from .types import UserType
class Query(graphene.ObjectType):
user = DjangoObjectField(UserType, description='Single User query')
Features: - Automatic ID-based filtering - No need to define custom resolve function - Built-in error handling for non-existent objects
Usage in GraphQL:
DjangoFilterListField¶
Provides filtering capabilities for list queries without pagination.
from django_graphex import DjangoFilterListField
from .types import UserType
class Query(graphene.ObjectType):
users = DjangoFilterListField(UserType)
Features:
- Built on Django's ORM lookups + Q objects (no django-filter)
- Multiple filter types (exact, contains, etc.)
- No pagination (returns all matching results)
Usage in GraphQL:
DjangoFilterPaginateListField¶
Combines filtering and pagination for list queries.
from django_graphex import DjangoFilterPaginateListField
from django_graphex.paginations import LimitOffsetGraphqlPagination
from .types import UserType
class Query(graphene.ObjectType):
users = DjangoFilterPaginateListField(
UserType,
pagination=LimitOffsetGraphqlPagination(default_limit=20)
)
Features: - All filtering capabilities of DjangoFilterListField - Built-in pagination support - Configurable pagination class
Usage in GraphQL:
{
users(filter: { firstName: { icontains: "john" } }, limit: 10, offset: 0) {
id
username
firstName
}
}
Flat list
DjangoFilterPaginateListField returns a flat list, so both the filter
arguments and the pagination/ordering arguments (limit, offset,
ordering) live directly on the list field. There is no results /
totalCount wrapper — for that, use DjangoListObjectField.
DjangoListObjectField¶
Recommended for Queries
This is the most flexible approach for list queries with built-in support for filtering and pagination.
from django_graphex import DjangoListObjectField
from .types import UserListType
class Query(graphene.ObjectType):
users = DjangoListObjectField(UserListType, description='All Users query')
Features:
- Works with DjangoListObjectType
- Inherits pagination configuration from the type
- Filtering via the type's filter_fields (built on Django ORM lookups + Q)
- Built-in caching support
Usage in GraphQL:
Filter arguments live on the list field; pagination and ordering arguments
(limit, offset, ordering) live on the results subfield. totalCount is
a sibling of results.
{
users(filter: { isActive: { exact: true } }) {
results(limit: 10, offset: 0, ordering: "-id") {
id
username
firstName
}
totalCount
}
}
Custom filtering logic¶
There are no FilterSet classes. Declarative lookups come from the type's
Meta.filter_fields and are queried through the nested filter: argument. For
bespoke rules (e.g. a free-text search across several columns), override
get_queryset / filter_queryset on a DjangoModelType:
from django.db.models import Q
from django_graphex import DjangoModelType
from django.contrib.auth.models import User
class UserType(DjangoModelType):
class Meta:
model = User
filter_fields = {"username": ("icontains",), "email": ("icontains",)}
@classmethod
def filter_queryset(cls, qs, info, **kwargs):
term = info.context.GET.get("q") if hasattr(info.context, "GET") else None
if term:
qs = qs.filter(
Q(first_name__icontains=term) | Q(last_name__icontains=term)
)
return qs
See Permissions & hooks and the Filtering guide.
Custom resolvers¶
DjangoObjectField, DjangoFilterListField, DjangoFilterPaginateListField and
DjangoListObjectField accept a custom resolver=. When given, it is used
instead of the built-in resolver — but it still receives the library's plumbing as
its leading positional arguments, so you can reuse filtering/pagination and
only change the base queryset:
- single object:
resolver(manager, root, info, **kwargs) - lists:
resolver(manager, filter_backend, root, info, **kwargs)
def active_users(manager, root, info, **kwargs):
# custom base queryset; manager is the model's default manager
return manager.filter(is_active=True).get(pk=kwargs["id"])
field = DjangoObjectField(UserType, resolver=active_users)
This is also what powers DjangoModelType.RetrieveField() / ListField()
(which inject cls.retrieve / cls.list), so a DjangoModelType.Meta.queryset
is honored by its list/retrieve.
Field Comparison¶
| Feature | DjangoObjectField | DjangoFilterListField | DjangoFilterPaginateListField | DjangoListObjectField |
|---|---|---|---|---|
| Single Objects | ✅ | ❌ | ❌ | ❌ |
| List Objects | ❌ | ✅ | ✅ | ✅ |
| Filtering | ID only | ✅ | ✅ | ✅ |
| Pagination | ❌ | ❌ | ✅ | ✅ |
| Custom queryset hooks | ❌ | ✅ | ✅ | ✅ |
| Type Integration | Basic | Basic | Basic | Full |
| Caching | ❌ | ❌ | ❌ | ✅ |
Best Practices¶
1. Use DjangoListObjectField for Lists¶
# ✅ Recommended
class Query(graphene.ObjectType):
users = DjangoListObjectField(UserListType, description='All users')
# ❌ Less flexible
class Query(graphene.ObjectType):
users = DjangoFilterPaginateListField(UserType)
2. Define Filter Fields in Types¶
class UserType(DjangoObjectType):
class Meta:
model = User
filter_fields = {
"username": ("exact", "icontains"),
"email": ("exact", "icontains"),
"is_active": ("exact",),
}
3. Use Descriptive Names¶
class Query(graphene.ObjectType):
# ✅ Clear and descriptive
active_users = DjangoListObjectField(
UserListType,
description='List of active users with pagination'
)
user_by_id = DjangoObjectField(
UserType,
description='Get a single user by ID'
)
4. Combine with Permissions¶
Pass a custom resolver= that reuses the library's plumbing (it receives
manager, filter_backend, root, info, **kwargs for list fields) and only changes
the base queryset; filter_backend.apply(qs, kwargs.get("filter")) applies the
nested filter: argument:
from django_graphex import DjangoListObjectField
from django_graphex.base_types import DjangoListObjectBase
from graphql import GraphQLError
def staff_only_users(manager, filter_backend, root, info, **kwargs):
if not info.context.user.is_staff:
raise GraphQLError("Staff access required")
qs = manager.get_queryset()
qs = filter_backend.apply(qs, kwargs.get("filter"))
return DjangoListObjectBase(count=qs.count(), results=qs)
class Query(graphene.ObjectType):
users = DjangoListObjectField(UserListType, resolver=staff_only_users)