How Django works (3): Testing Server and Static Files Serving
How Django Handles Static Files
By default, Django installs an Application django.contrib.staticfiles, which is responsible for handling requests to files under STATIC_URL.INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'polls', )
STATIC_URL = '/static/'
This method is grossly inefficient and probably insecure, so it is unsuitable for production. https://docs.djangoproject.com/en/1.8/howto/static-files/deployment/
How staticfiles App Works
Based on the first blog of Django series, Django interacts with web servers by providing a callable application that conforms to WSGI specification.1 2 3 4 5 | class WSGIHandler(base.BaseHandler): initLock = Lock() request_class = WSGIRequest def __call__(self, environ, start_response): |
What staticfiles app does is that it wraps the original callable application.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class StaticFilesHandler(WSGIHandler): """ WSGI middleware that intercepts calls to the static files directory, as defined by the STATIC_URL setting, and serves those files. """ # 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(StaticFilesHandler, self).__init__() ... def __call__(self, environ, start_response): if not self._should_handle(get_path_info(environ)): return self.application(environ, start_response) return super(StaticFilesHandler, self).__call__(environ, start_response) |
application is the callable application provided in wsgi.py. Whenever a request is from a webserver, it invokes StaticFilesHandler.__call__ instead of WSGIHandler.__call__.
Line 17 checks to see if the requested path is /static/:
if not true, self.application is called, otherwise super(StaticFilesHandler, self) is called.
Both invocations actually executes the same code:
- self.application is an object of WSGIHandler, so WSGIHandler.__call__ is executed;
- StaticFilesHandler inherits WSGIHandler, so super().__call__ refers to WSGIHandler.__call__.
Same Code for Static Files and non Static Files?
How are two invocations different when they are running the same code?The answer is that they manipulate different data -- one is self.application, and the other self. self.application is an object of WSGIHandler whereas self is an object of StaticFilesHandler.
WSGI Middleware or Convenient Workaround
Calling StaticFilesHandler a WSGI middleware is a misnomer to me, the reason is that in our static "middleware", nothing special happens. The added behavior is provided by WSGIHandler.__call__ processing different data. In other words, StaticFilesHandler must have knowledge of internal workings of WSGIHandler to work, especially how WSGIHandler utilize data in the instance __dict__.A true middleware should be transparent and only do preprocessing and postprocessing,included but not limited to (see https://www.python.org/dev/peps/pep-3333/#middleware-components-that-play-both-sides):
- Routing a request to different application objects based on the target URL, after rewriting the environ accordingly;
- Allowing multiple applications or frameworks to run side-by-side in the same process;
- Load balancing and remote processing, by forwarding requests and responses over a network;
- Perform content postprocessing, such as applying XSL stylesheets.