Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions django/conf/project_template/project_name/asgi.py-tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for {{ project_name }} project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/{{ docs_version }}/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{{ project_name }}.settings')

application = get_asgi_application()
41 changes: 33 additions & 8 deletions django/contrib/staticfiles/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,20 @@
from django.conf import settings
from django.contrib.staticfiles import utils
from django.contrib.staticfiles.views import serve
from django.core.handlers.asgi import ASGIHandler
from django.core.handlers.exception import response_for_exception
from django.core.handlers.wsgi import WSGIHandler, get_path_info
from django.http import Http404


class StaticFilesHandler(WSGIHandler):
class StaticFilesHandlerMixin:
"""
WSGI middleware that intercepts calls to the static files directory, as
defined by the STATIC_URL setting, and serves those files.
Common methods used by WSGI and ASGI handlers.
"""
# May be used to differentiate between handler types (e.g. in a
# request_finished signal)
handles_files = True

def __init__(self, application):
self.application = application
self.base_url = urlparse(self.get_base_url())
super().__init__()

def load_middleware(self):
# Middleware are already loaded for self.application; no need to reload
# them for self.
Expand Down Expand Up @@ -57,7 +52,37 @@ def get_response(self, request):
except Http404 as e:
return response_for_exception(request, e)


class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):
"""
WSGI middleware that intercepts calls to the static files directory, as
defined by the STATIC_URL setting, and serves those files.
"""
def __init__(self, application):
self.application = application
self.base_url = urlparse(self.get_base_url())
super().__init__()

def __call__(self, environ, start_response):
if not self._should_handle(get_path_info(environ)):
return self.application(environ, start_response)
return super().__call__(environ, start_response)


class ASGIStaticFilesHandler(StaticFilesHandlerMixin, ASGIHandler):
"""
ASGI application which wraps another and intercepts requests for static
files, passing them off to Django's static file serving.
"""
def __init__(self, application):
self.application = application
self.base_url = urlparse(self.get_base_url())

async def __call__(self, scope, receive, send):
# Only even look at HTTP requests
if scope['type'] == 'http' and self._should_handle(scope['path']):
# Serve static content
# (the one thing super() doesn't do is __call__, apparently)
return await super().__call__(scope, receive, send)
# Hand off to the main app
return await self.application(scope, receive, send)
13 changes: 13 additions & 0 deletions django/core/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import django
from django.core.handlers.asgi import ASGIHandler


def get_asgi_application():
"""
The public interface to Django's ASGI support. Return an ASGI 3 callable.

Avoids making django.core.handlers.ASGIHandler a public API, in case the
internal implementation changes or moves in the future.
"""
django.setup(set_prefix=False)
return ASGIHandler()
10 changes: 10 additions & 0 deletions django/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class RequestDataTooBig(SuspiciousOperation):
pass


class RequestAborted(Exception):
"""The request was closed before it was completed, or timed out."""
pass


class PermissionDenied(Exception):
"""The user did not have permission to do that"""
pass
Expand Down Expand Up @@ -181,3 +186,8 @@ def __repr__(self):
class EmptyResultSet(Exception):
"""A database query predicate is impossible."""
pass


class SynchronousOnlyOperation(Exception):
"""The user tried to call a sync-only function from an async context."""
pass
Loading