Skip to main content

Handling Requests and Routing

Handling requests and routing in this codebase revolves around a structured cycle where incoming web requests are mapped to specific view functions or classes, which then process the data and return an appropriate response. This process is primarily managed through the HttpRequest and HttpResponse classes, and the URL configuration system.

URL Routing

Routing is defined in URLconf modules using the urlpatterns list. This list contains mappings created with the path() and re_path() functions found in django/urls/conf.py.

Path and Re_path

The path() function allows for simple, readable URL patterns with route converters, while re_path() uses regular expressions for more complex matching.

# django/urls/conf.py

path = partial(_path, Pattern=RoutePattern)
re_path = partial(_path, Pattern=RegexPattern)

In practice, these are used to map URL strings to view callables. For example, in tests/generic_views/urls.py:

from django.urls import path
from . import views

urlpatterns = [
# Using a route converter <int:pk>
path("detail/artist/<int:pk>/", views.ArtistDetail.as_view(), name="artist_detail"),
# Using a simple string match
path("template/simple/<foo>/", views.SimpleTemplate.as_view()),
]

The Request Object

Every view receives an instance of HttpRequest as its first argument. This class, defined in django/http/request.py, encapsulates all metadata and data sent by the client.

Accessing Request Data

Data sent via GET or POST is stored in QueryDict objects, which are specialized dictionaries that handle multiple values for the same key.

  • request.GET: Contains all HTTP GET parameters.
  • request.POST: Contains all HTTP POST parameters, provided the request has a form-related content type.
  • request.FILES: A MultiValueDict containing all uploaded files.

Note on Immutability: QueryDict instances (like request.GET and request.POST) are immutable by default. To modify them, you must create a copy:

# django/http/request.py

def _assert_mutable(self):
if not self._mutable:
raise AttributeError("This QueryDict instance is immutable")

Headers and Metadata

The HttpRequest.headers property provides case-insensitive access to all request headers.

# django/http/request.py

@cached_property
def headers(self):
return HttpHeaders(self.META)

Other useful attributes include:

  • request.method: The HTTP verb (e.g., 'GET', 'POST').
  • request.path: The full path to the requested page, not including the domain or query string.
  • request.META: A standard Python dictionary containing all available HTTP headers and environment variables.

Views

Views are the logic layer of the application. They can be implemented as simple functions (Function-Based Views) or as classes (Class-Based Views).

Class-Based Views (CBVs)

The View class in django/views/generic/base.py provides the foundation for CBVs. It uses a dispatch() method to route requests to the appropriate handler method based on the HTTP verb (e.g., get(), post()).

To use a CBV in a URLconf, you must call its as_view() class method, which returns a callable that handles the request-response cycle for that class.

# django/views/generic/base.py

@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
return self.dispatch(request, *args, **kwargs)
return view

View Dispatching

The dispatch() method inspects request.method and attempts to call a method on the class with the same name.

# django/views/generic/base.py

def dispatch(self, request, *args, **kwargs):
method = request.method.lower()
if method in self.http_method_names:
handler = getattr(self, method, self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)

The Response Object

Every view must return an HttpResponse object (or a subclass). The base HttpResponse class is defined in django/http/response.py.

Common Response Types

  • HttpResponse: The standard response for text/html content.
  • JsonResponse: A subclass that converts a dictionary into a JSON-encoded response and sets the Content-Type to application/json.
  • HttpResponseRedirect: Returns a 302 status code to redirect the client to a different URL.
  • StreamingHttpResponse: Used for large responses where content is generated on the fly and should not be buffered in memory.
# django/http/response.py

class HttpResponse(HttpResponseBase):
def __init__(self, content=b"", *args, **kwargs):
super().__init__(*args, **kwargs)
self.content = content

Response Metadata

You can set headers and cookies directly on the response object:

response = HttpResponse("Hello World")
response["X-Custom-Header"] = "Value"
response.set_cookie("my_cookie", "cookie_value")

Shortcuts

The django/shortcuts.py module provides helper functions that simplify common tasks.

Render

The render() shortcut combines a template with a context dictionary and returns an HttpResponse object with the rendered text.

# django/shortcuts.py

def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)

Redirect

The redirect() shortcut returns an HttpResponseRedirect to the appropriate URL for the arguments passed. It can accept a model, a view name, or a specific URL.

# django/shortcuts.py

def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))

Advanced Request Handling

Data Limits

To prevent Denial of Service (DoS) attacks, the codebase enforces limits on the size and complexity of incoming requests via settings:

  • DATA_UPLOAD_MAX_MEMORY_SIZE: Limits the size of the request body read into memory.
  • DATA_UPLOAD_MAX_NUMBER_FIELDS: Limits the number of parameters in GET or POST data.

If these limits are exceeded, the HttpRequest will raise RequestDataTooBig or TooManyFieldsSent respectively.

Host Validation

The get_host() method validates the Host header against the ALLOWED_HOSTS setting to prevent HTTP Host header attacks.

# django/http/request.py

def get_host(self):
host = self._get_raw_host()
allowed_hosts = settings.ALLOWED_HOSTS
# ... validation logic ...
if domain and validate_host(domain, allowed_hosts):
return host
else:
raise DisallowedHost(msg)