CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework-stubs

PEP 484 type stubs for Django REST Framework enabling static type checking with comprehensive type definitions for all major DRF components

Pending
Overview
Eval results
Files

requests-responses.mddocs/

Requests & Responses

Django REST Framework provides enhanced Request and Response objects that extend Django's base HTTP handling with additional features for API development. The type stubs ensure complete type safety for request parsing, response rendering, and content negotiation.

Request Object

Request Class

class Request(HttpRequest):
    """Enhanced request object with DRF-specific functionality."""
    
    # Parser and authentication configuration
    parsers: Sequence[BaseParser] | None
    authenticators: Sequence[BaseAuthentication | ForcedAuthentication] | None  
    negotiator: BaseContentNegotiation | None
    
    # Content negotiation results
    accepted_renderer: BaseRenderer
    accepted_media_type: str
    
    # Authentication results
    user: AbstractUser | AnonymousUser
    auth: Any  # Token, session, or custom auth object
    
    # Parsed data properties
    @property
    def data(self) -> dict[str, Any]:
        """
        Parsed request data from request body.
        
        Returns:
            dict[str, Any]: Parsed data (JSON, form data, etc.)
        """
        ...
    
    @property
    def query_params(self) -> QueryDict:
        """
        Query parameters from URL (immutable).
        
        Returns:
            QueryDict: URL query parameters
        """
        ...
    
    def __init__(
        self,
        request: HttpRequest,
        parsers: Sequence[BaseParser] | None = None,
        authenticators: Sequence[BaseAuthentication] | None = None,
        negotiator: BaseContentNegotiation | None = None,
        parser_context: dict[str, Any] | None = None
    ) -> None: ...

Key Properties:

  • data: dict[str, Any] - Parsed request body (JSON, form data, files)
  • query_params: QueryDict - URL query parameters (immutable)
  • user: AbstractUser | AnonymousUser - Authenticated user or anonymous user
  • auth: Any - Authentication object (token, session data, etc.)

Request Utilities

def is_form_media_type(media_type: str) -> bool:
    """
    Check if media type is form-encoded.
    
    Args:
        media_type: Content-Type header value
        
    Returns:
        bool: True if form media type
    """
    ...

def clone_request(request: Request, method: str) -> Request:
    """
    Clone a request with a different HTTP method.
    
    Args:
        request: Original request object
        method: New HTTP method
        
    Returns:
        Request: Cloned request with new method
    """
    ...

ForcedAuthentication

class ForcedAuthentication:
    """Force authentication for testing purposes."""
    
    def __init__(self, user: AbstractUser, token: Any = None) -> None: ...

Parameters:

  • user: AbstractUser - User to authenticate as
  • token: Any - Optional authentication token

Empty Data Markers

class Empty:
    """Marker class for empty request data."""
    pass

# Singleton instance
empty: Empty

Response Object

Response Class

class Response(SimpleTemplateResponse):
    """Enhanced response object with DRF functionality."""
    
    # Response data and metadata
    data: Any
    exception: bool
    content_type: str | None
    
    # Content negotiation results  
    accepted_renderer: BaseRenderer
    accepted_media_type: str
    renderer_context: dict[str, Any]
    
    def __init__(
        self,
        data: Any = None,
        status: int | None = None,
        template_name: str | list[str] | None = None,
        headers: dict[str, str] | None = None,
        exception: bool = False,
        content_type: str | None = None
    ) -> None: ...
    
    @property
    def rendered_content(self) -> bytes:
        """Get rendered response content."""
        ...
    
    @property
    def status_text(self) -> str:
        """Get HTTP status text."""
        ...
    
    def render(self) -> Response:
        """
        Render the response content using the configured renderer.
        
        Returns:
            Response: Self after rendering
        """
        ...

Parameters:

  • data: Any - Response data to serialize
  • status: int | None - HTTP status code
  • template_name: str | list[str] | None - Template for HTML responses
  • headers: dict[str, str] | None - Additional HTTP headers
  • exception: bool - Whether response represents an exception
  • content_type: str | None - Override content type

Request Processing Examples

Accessing Request Data

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class BookCreateView(APIView):
    """Demonstrate request data access."""
    
    def post(self, request: Request) -> Response:
        """Handle POST request with data parsing."""
        
        # Access parsed JSON/form data
        title = request.data.get('title')
        author_id = request.data.get('author_id')
        
        # Access query parameters
        format_type = request.query_params.get('format', 'json')
        include_meta = request.query_params.get('include_meta', 'false').lower() == 'true'
        
        # Access authentication info
        user = request.user
        auth_token = request.auth
        
        # Access request metadata
        content_type = request.content_type
        method = request.method
        
        # Validate and process data
        if not title or not author_id:
            return Response(
                {'error': 'Title and author_id are required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Create book instance
        book = Book.objects.create(
            title=title,
            author_id=author_id,
            created_by=user if user.is_authenticated else None
        )
        
        # Return response based on format preference
        response_data = {
            'id': book.id,
            'title': book.title,
            'author_id': book.author_id
        }
        
        if include_meta:
            response_data['meta'] = {
                'created_by': user.username if user.is_authenticated else None,
                'created_at': book.created_at.isoformat(),
                'format': format_type
            }
        
        return Response(response_data, status=status.HTTP_201_CREATED)

File Upload Handling

from django.core.files.storage import default_storage

class FileUploadView(APIView):
    """Handle file uploads with request data access."""
    
    def post(self, request: Request) -> Response:
        """Process file upload request."""
        
        # Access uploaded files
        uploaded_file = request.data.get('file')
        if not uploaded_file:
            return Response(
                {'error': 'No file provided'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Access additional form fields
        title = request.data.get('title', uploaded_file.name)
        description = request.data.get('description', '')
        
        # Validate file
        if uploaded_file.size > 10 * 1024 * 1024:  # 10MB limit
            return Response(
                {'error': 'File too large'},
                status=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE
            )
        
        # Save file
        file_path = default_storage.save(
            f"uploads/{uploaded_file.name}",
            uploaded_file
        )
        
        # Create database record
        document = Document.objects.create(
            title=title,
            description=description,
            file_path=file_path,
            uploaded_by=request.user
        )
        
        return Response({
            'id': document.id,
            'title': document.title,
            'file_url': default_storage.url(file_path)
        }, status=status.HTTP_201_CREATED)

Response Creation Examples

Basic Response Patterns

from rest_framework.response import Response
from rest_framework import status

class BookDetailView(APIView):
    """Demonstrate various response patterns."""
    
    def get(self, request: Request, pk: int) -> Response:
        """Return different response types based on conditions."""
        
        try:
            book = Book.objects.get(pk=pk)
        except Book.DoesNotExist:
            # Error response with custom status
            return Response(
                {'error': 'Book not found'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        # Check permissions
        if book.is_private and request.user != book.owner:
            return Response(
                {'error': 'Access denied'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        # Success response with data
        serializer = BookSerializer(book, context={'request': request})
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    def put(self, request: Request, pk: int) -> Response:
        """Update with validation response patterns."""
        
        try:
            book = Book.objects.get(pk=pk)
        except Book.DoesNotExist:
            return Response(
                {'error': 'Book not found'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        # Validate and update
        serializer = BookSerializer(book, data=request.data, partial=False)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            # Validation error response
            return Response(
                serializer.errors,
                status=status.HTTP_400_BAD_REQUEST
            )
    
    def delete(self, request: Request, pk: int) -> Response:
        """Delete with empty response."""
        
        try:
            book = Book.objects.get(pk=pk)
            book.delete()
            # Empty success response
            return Response(status=status.HTTP_204_NO_CONTENT)
        except Book.DoesNotExist:
            return Response(
                {'error': 'Book not found'},
                status=status.HTTP_404_NOT_FOUND
            )

Custom Headers and Content Types

class CustomResponseView(APIView):
    """Demonstrate custom response headers and content types."""
    
    def get(self, request: Request) -> Response:
        """Response with custom headers."""
        
        data = {'message': 'Custom response'}
        headers = {
            'X-Custom-Header': 'Custom Value',
            'X-Request-ID': str(uuid.uuid4()),
            'Cache-Control': 'no-cache, no-store',
        }
        
        return Response(
            data,
            status=status.HTTP_200_OK,
            headers=headers
        )
    
    def post(self, request: Request) -> Response:
        """Response with custom content type."""
        
        # Process request data
        result = {'processed': True, 'timestamp': timezone.now().isoformat()}
        
        return Response(
            result,
            status=status.HTTP_201_CREATED,
            content_type='application/vnd.api+json'
        )

Conditional Responses

class ConditionalResponseView(APIView):
    """Demonstrate conditional response handling."""
    
    def get(self, request: Request) -> Response:
        """Return different responses based on request parameters."""
        
        # Check for format preference
        format_param = request.query_params.get('format', 'json')
        
        if format_param == 'xml':
            return Response(
                {'message': 'XML format requested'},
                content_type='application/xml'
            )
        elif format_param == 'csv':
            # Return CSV data
            csv_data = "id,name,value\n1,test,100"
            return Response(
                csv_data,
                content_type='text/csv',
                headers={'Content-Disposition': 'attachment; filename="data.csv"'}
            )
        else:
            # Default JSON response
            return Response({
                'data': ['item1', 'item2', 'item3'],
                'format': 'json'
            })

Advanced Request/Response Handling

Request Method Override

from rest_framework.request import override_method

class MethodOverrideView(APIView):
    """Handle method override for clients that don't support all HTTP methods."""
    
    def post(self, request: Request) -> Response:
        """Handle POST with method override."""
        
        # Check for method override header
        override_method_header = request.META.get('HTTP_X_HTTP_METHOD_OVERRIDE')
        
        if override_method_header:
            with override_method(request, override_method_header):
                if override_method_header.upper() == 'PUT':
                    return self.put(request)
                elif override_method_header.upper() == 'PATCH':
                    return self.patch(request)
                elif override_method_header.upper() == 'DELETE':
                    return self.delete(request)
        
        # Regular POST handling
        return Response({'method': 'POST'})
    
    def put(self, request: Request) -> Response:
        return Response({'method': 'PUT'})
    
    def patch(self, request: Request) -> Response:
        return Response({'method': 'PATCH'})
    
    def delete(self, request: Request) -> Response:
        return Response({'method': 'DELETE'})

Streaming Responses

import json
from django.http import StreamingHttpResponse

class StreamingResponseView(APIView):
    """Handle large dataset streaming."""
    
    def get(self, request: Request) -> StreamingHttpResponse:
        """Stream large JSON response."""
        
        def generate_data():
            """Generator function for streaming data."""
            yield '{"items": ['
            
            first = True
            for book in Book.objects.iterator(chunk_size=1000):
                if not first:
                    yield ','
                first = False
                
                book_data = {
                    'id': book.id,
                    'title': book.title,
                    'author': book.author.name if book.author else None
                }
                yield json.dumps(book_data)
            
            yield ']}'
        
        response = StreamingHttpResponse(
            generate_data(),
            content_type='application/json'
        )
        response['Content-Disposition'] = 'attachment; filename="books.json"'
        return response

Request Context and Metadata

class RequestContextView(APIView):
    """Access comprehensive request context information."""
    
    def get(self, request: Request) -> Response:
        """Return detailed request context."""
        
        context = {
            # HTTP Information
            'method': request.method,
            'path': request.path,
            'full_path': request.get_full_path(),
            'scheme': request.scheme,
            'is_secure': request.is_secure(),
            
            # Authentication
            'user': {
                'username': request.user.username if request.user.is_authenticated else None,
                'is_authenticated': request.user.is_authenticated,
                'is_staff': getattr(request.user, 'is_staff', False),
            },
            'auth_type': type(request.auth).__name__ if request.auth else None,
            
            # Content Information
            'content_type': request.content_type,
            'accepted_media_type': getattr(request, 'accepted_media_type', None),
            'accepted_renderer': type(getattr(request, 'accepted_renderer', None)).__name__,
            
            # Client Information
            'user_agent': request.META.get('HTTP_USER_AGENT'),
            'remote_addr': request.META.get('REMOTE_ADDR'),
            'host': request.get_host(),
            
            # Data Summary
            'has_data': bool(request.data),
            'data_keys': list(request.data.keys()) if request.data else [],
            'query_params': dict(request.query_params),
        }
        
        return Response(context)

Error Response Patterns

Standardized Error Responses

class ErrorResponseView(APIView):
    """Demonstrate standardized error response patterns."""
    
    def post(self, request: Request) -> Response:
        """Handle request with comprehensive error handling."""
        
        try:
            # Validate required fields
            required_fields = ['name', 'email']
            missing_fields = []
            
            for field in required_fields:
                if field not in request.data:
                    missing_fields.append(field)
            
            if missing_fields:
                return Response({
                    'error': 'Missing required fields',
                    'code': 'MISSING_FIELDS',
                    'details': {
                        'missing_fields': missing_fields
                    }
                }, status=status.HTTP_400_BAD_REQUEST)
            
            # Validate email format
            email = request.data['email']
            if '@' not in email:
                return Response({
                    'error': 'Invalid email format',
                    'code': 'INVALID_EMAIL',
                    'details': {
                        'field': 'email',
                        'value': email
                    }
                }, status=status.HTTP_400_BAD_REQUEST)
            
            # Process successful request
            return Response({
                'message': 'Success',
                'data': request.data
            }, status=status.HTTP_201_CREATED)
            
        except Exception as e:
            # Handle unexpected errors
            return Response({
                'error': 'Internal server error',
                'code': 'INTERNAL_ERROR',
                'details': {
                    'message': str(e) if settings.DEBUG else 'An unexpected error occurred'
                }
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

Response Formatting Middleware

class ResponseFormatView(APIView):
    """Demonstrate consistent response formatting."""
    
    def format_success_response(
        self, 
        data: Any, 
        message: str = 'Success',
        status_code: int = status.HTTP_200_OK
    ) -> Response:
        """Format successful response with consistent structure."""
        
        response_data = {
            'success': True,
            'message': message,
            'data': data,
            'timestamp': timezone.now().isoformat()
        }
        
        return Response(response_data, status=status_code)
    
    def format_error_response(
        self, 
        error: str, 
        code: str | None = None,
        details: dict[str, Any] | None = None,
        status_code: int = status.HTTP_400_BAD_REQUEST
    ) -> Response:
        """Format error response with consistent structure."""
        
        response_data = {
            'success': False,
            'error': error,
            'code': code,
            'details': details or {},
            'timestamp': timezone.now().isoformat()
        }
        
        return Response(response_data, status=status_code)
    
    def get(self, request: Request) -> Response:
        """Example using formatted responses."""
        
        books = Book.objects.all()[:10]
        serializer = BookSerializer(books, many=True)
        
        return self.format_success_response(
            data=serializer.data,
            message='Books retrieved successfully'
        )

This comprehensive request and response system provides type-safe HTTP handling with full mypy support, enabling confident API development with proper request parsing, response formatting, and error handling patterns.

Install with Tessl CLI

npx tessl i tessl/pypi-djangorestframework-stubs

docs

authentication-permissions.md

exceptions-status.md

fields-relations.md

index.md

pagination-filtering.md

requests-responses.md

routers-urls.md

serializers.md

views-viewsets.md

tile.json