CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-graphene-django

Django integration for Graphene enabling GraphQL APIs in Django applications

Pending
Overview
Eval results
Files

debug.mddocs/

Debug Tools

Development debugging tools for GraphQL queries with SQL query inspection, performance monitoring, and comprehensive middleware integration. Provides detailed insights into GraphQL execution and database query patterns.

Capabilities

DjangoDebugMiddleware

Middleware to capture SQL queries and timing information during GraphQL execution with detailed performance metrics.

class DjangoDebugMiddleware:
    """
    Middleware to capture SQL queries and timing information.
    
    Captures all SQL queries executed during GraphQL field resolution
    with timing, parameters, and performance analysis for development
    and debugging purposes.
    """
    
    def __init__(self):
        """Initialize debug middleware with query tracking."""
    
    def resolve(self, next, root, info, **args):
        """
        Middleware resolver function with SQL tracking.
        
        Parameters:
        - next: Next resolver in chain
        - root: GraphQL root object
        - info: GraphQL execution info
        - **args: Resolver arguments
        
        Returns:
        Resolver result with debug information attached
        """

DjangoDebug

Debug information container for GraphQL queries with comprehensive SQL query details and execution metrics.

class DjangoDebug(graphene.ObjectType):
    """
    Debug information container for GraphQL queries.
    
    Provides structured access to SQL queries, timing information,
    and performance metrics captured during GraphQL execution.
    """
    sql = graphene.List(DjangoDebugSQL)
    
    def resolve_sql(self, info):
        """
        Resolve SQL queries from debug context.
        
        Parameters:
        - info: GraphQL execution info
        
        Returns:
        List[DjangoDebugSQL]: List of executed SQL queries
        """

DjangoDebugSQL

Individual SQL query debug information with comprehensive query analysis and performance metrics.

class DjangoDebugSQL(graphene.ObjectType):
    """
    Individual SQL query debug information.
    
    Detailed information about each SQL query executed during
    GraphQL resolution including timing, parameters, and metadata.
    """
    vendor = graphene.String()                 # Database vendor (postgresql, mysql, etc.)
    alias = graphene.String()                  # Database alias/connection name
    sql = graphene.String()                    # Formatted SQL query
    duration = graphene.Float()                # Query execution time in seconds
    raw_sql = graphene.String()                # Raw SQL with parameter placeholders
    params = graphene.String()                 # Query parameters as JSON string
    start_time = graphene.Float()              # Query start timestamp
    stop_time = graphene.Float()               # Query completion timestamp
    is_slow = graphene.Boolean()               # Whether query exceeds slow threshold
    is_select = graphene.Boolean()             # Whether query is SELECT statement
    trans_id = graphene.String()               # Transaction ID
    trans_status = graphene.String()           # Transaction status
    iso_level = graphene.String()              # Postgres isolation level if available
    encoding = graphene.String()               # Database encoding
    
    def resolve_duration(self, info):
        """
        Calculate query duration in seconds.
        
        Returns:
        float: Duration in seconds
        """
    
    def resolve_is_slow(self, info):
        """
        Determine if query exceeds slow query threshold.
        
        Returns:
        bool: True if query is considered slow
        """
    
    def resolve_is_select(self, info):
        """
        Determine if query is a SELECT statement.
        
        Returns:
        bool: True if query is SELECT
        """
    
    def resolve_params(self, info):
        """
        Format query parameters as JSON string.
        
        Returns:
        str: JSON-formatted parameters
        """

Usage Examples

Basic Debug Setup

from graphene_django.debug import DjangoDebugMiddleware, DjangoDebug
import graphene

class Query(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug)
    users = graphene.List(UserType)
    
    def resolve_users(self, info):
        return User.objects.all()

schema = graphene.Schema(
    query=Query,
    middleware=[DjangoDebugMiddleware()]
)

# GraphQL query with debug info:
# query {
#   users {
#     id
#     username
#   }
#   debug {
#     sql {
#       sql
#       duration
#       vendor
#     }
#   }
# }

Development View Configuration

from django.conf import settings
from graphene_django.views import GraphQLView
from graphene_django.debug import DjangoDebugMiddleware

def create_graphql_view():
    middleware = []
    
    if settings.DEBUG:
        middleware.append(DjangoDebugMiddleware())
    
    return GraphQLView.as_view(
        schema=schema,
        middleware=middleware,
        graphiql=settings.DEBUG
    )

# urls.py
urlpatterns = [
    path('graphql/', create_graphql_view()),
]

Custom Debug Schema

class DebugQuery(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug)
    
    def resolve_debug(self, info):
        # Custom debug information
        return DjangoDebug()

class Query(DebugQuery, graphene.ObjectType):
    users = graphene.List(UserType)
    posts = graphene.List(PostType)
    
    def resolve_users(self, info):
        # This will be tracked by debug middleware
        return User.objects.select_related('profile').all()
    
    def resolve_posts(self, info):
        # Complex query for debugging
        return Post.objects.select_related('author').prefetch_related('tags').all()

schema = graphene.Schema(
    query=Query,
    middleware=[DjangoDebugMiddleware()]
)

Conditional Debug Information

from django.conf import settings

class ConditionalDebugMiddleware:
    def __init__(self):
        self.debug_middleware = DjangoDebugMiddleware() if settings.DEBUG else None
    
    def resolve(self, next, root, info, **args):
        if self.debug_middleware:
            return self.debug_middleware.resolve(next, root, info, **args)
        return next(root, info, **args)

class Query(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug)
    users = graphene.List(UserType)
    
    def resolve_debug(self, info):
        if not settings.DEBUG:
            raise Exception("Debug information not available in production")
        return DjangoDebug()

schema = graphene.Schema(
    query=Query,
    middleware=[ConditionalDebugMiddleware()]
)

Performance Analysis

class PerformanceQuery(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug)
    users = graphene.List(UserType)
    
    def resolve_users(self, info):
        # Intentionally inefficient query for debugging
        users = []
        for user in User.objects.all():
            # This creates N+1 query problem
            user.post_count = user.post_set.count()
            users.append(user)
        return users

# GraphQL query to analyze performance:
# query {
#   users {
#     id
#     username
#   }
#   debug {
#     sql {
#       sql
#       duration
#       isSelect
#       isSlow
#     }
#   }
# }

Custom Debug Middleware

import time
import logging
from graphene_django.debug import DjangoDebugMiddleware

logger = logging.getLogger(__name__)

class CustomDebugMiddleware(DjangoDebugMiddleware):
    def resolve(self, next, root, info, **args):
        start_time = time.time()
        
        # Call parent middleware
        result = super().resolve(next, root, info, **args)
        
        end_time = time.time()
        duration = end_time - start_time
        
        # Log slow resolvers
        if duration > 0.1:  # 100ms threshold
            logger.warning(
                f"Slow resolver: {info.field_name} took {duration:.3f}s"
            )
        
        # Add custom debug info
        if hasattr(info.context, 'debug'):
            info.context.debug['resolvers'] = getattr(
                info.context.debug, 'resolvers', []
            ) + [{
                'field': info.field_name,
                'duration': duration,
                'args': args
            }]
        
        return result

class ExtendedDebug(DjangoDebug):
    resolvers = graphene.List(graphene.JSONString)
    
    def resolve_resolvers(self, info):
        return getattr(info.context.debug, 'resolvers', [])

class Query(graphene.ObjectType):
    debug = graphene.Field(ExtendedDebug)
    users = graphene.List(UserType)

schema = graphene.Schema(
    query=Query,
    middleware=[CustomDebugMiddleware()]
)

Production Debug Safety

from django.core.exceptions import PermissionDenied

class SecureDebugMiddleware:
    def __init__(self):
        self.debug_middleware = DjangoDebugMiddleware()
    
    def resolve(self, next, root, info, **args):
        # Only enable debug for staff users
        if not getattr(info.context.user, 'is_staff', False):
            return next(root, info, **args)
        
        return self.debug_middleware.resolve(next, root, info, **args)

class SecureDebugQuery(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug)
    
    def resolve_debug(self, info):
        if not getattr(info.context.user, 'is_staff', False):
            raise PermissionDenied("Debug information requires staff access")
        return DjangoDebug()

class Query(SecureDebugQuery, graphene.ObjectType):
    users = graphene.List(UserType)

schema = graphene.Schema(
    query=Query,
    middleware=[SecureDebugMiddleware()]
)

GraphiQL Integration

# For GraphiQL development interface with debug info
from graphene_django.views import GraphQLView

class DebugGraphQLView(GraphQLView):
    def get_context(self, request):
        context = super().get_context(request)
        
        # Initialize debug context
        if settings.DEBUG:
            context['debug'] = {}
        
        return context

urlpatterns = [
    path('graphql/', DebugGraphQLView.as_view(
        schema=schema,
        middleware=[DjangoDebugMiddleware()],
        graphiql=settings.DEBUG
    )),
]

# In GraphiQL, you can now query:
# {
#   users { id username }
#   debug {
#     sql {
#       sql
#       duration
#       params
#     }
#   }
# }

Database Connection Analysis

class DatabaseDebugQuery(graphene.ObjectType):
    debug = graphene.Field(DjangoDebug)
    connection_info = graphene.Field(graphene.JSONString)
    
    def resolve_connection_info(self, info):
        if not settings.DEBUG:
            return None
        
        from django.db import connections
        
        connection_data = {}
        for alias in connections:
            conn = connections[alias]
            connection_data[alias] = {
                'vendor': conn.vendor,
                'settings': {
                    'ENGINE': conn.settings_dict.get('ENGINE'),
                    'NAME': conn.settings_dict.get('NAME'),
                    'HOST': conn.settings_dict.get('HOST'),
                    'PORT': conn.settings_dict.get('PORT'),
                }
            }
        
        return connection_data

# Query database connection info:
# query {
#   connectionInfo
#   debug {
#     sql {
#       alias
#       vendor
#       sql
#     }
#   }
# }

Install with Tessl CLI

npx tessl i tessl/pypi-graphene-django

docs

core-types.md

debug.md

fields.md

filtering.md

forms.md

index.md

rest-framework.md

testing.md

views.md

tile.json