Commit 8e96584f authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed #14524, #14582, #14617, #14665 and #14667 -- Tweaked staticfiles app.

* Updated StaticFilesHandler and AdminMediaHandler
  to make use of the 404 handler if needed.

* Updated runserver management command to serve static files
  only in DEBUG mode (or if specified the --insecure option)
  and if the staticfiles app is in INSTALLED_APPS. Also added
  an option to disable serving completely (--nostatic).

* Added check in debug mode if STATICFILES_* settings are
  different to MEDIA_* settings.

* Removed a faulty PendingDeprecationWarning in AdminMediaHandler
  that is triggered every time runserver is used.

* Fixed an issue with the modification time checks when
  running collectstatic.

* Extended and refined documentation.

Thanks to everyone for input, especially to Carl Meyer, Ted Kaemming and
Adam Vandenberg for patches.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14533 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 216fdfab
Loading
Loading
Loading
Loading
+38 −34
Original line number Diff line number Diff line
import os
import urllib
from urlparse import urlparse

from django.core.handlers.wsgi import WSGIHandler, STATUS_CODE_TEXT
from django.http import Http404
from django.conf import settings
from django.core.handlers.wsgi import WSGIHandler

from django.contrib.staticfiles import utils
from django.contrib.staticfiles.views import serve

class StaticFilesHandler(WSGIHandler):
@@ -18,16 +18,28 @@ class StaticFilesHandler(WSGIHandler):
            self.media_dir = media_dir
        else:
            self.media_dir = self.get_media_dir()
        self.media_url = self.get_media_url()
        self.media_url = urlparse(self.get_media_url())
        if settings.DEBUG:
            utils.check_settings()
        super(StaticFilesHandler, self).__init__()

    def get_media_dir(self):
        from django.conf import settings
        return settings.STATICFILES_ROOT

    def get_media_url(self):
        from django.conf import settings
        return settings.STATICFILES_URL

    def _should_handle(self, path):
        """
        Checks if the path should be handled. Ignores the path if:

        * the host is provided as part of the media_url
        * the request's path isn't under the media path (or equal)
        * settings.DEBUG isn't True
        """
        return (self.media_url[2] != path and
            path.startswith(self.media_url[2]) and not self.media_url[1])

    def file_path(self, url):
        """
        Returns the relative path to the media file on disk for the given URL.
@@ -37,36 +49,28 @@ class StaticFilesHandler(WSGIHandler):
        is raised.
        """
        # Remove ``media_url``.
        relative_url = url[len(self.media_url):]
        relative_url = url[len(self.media_url[2]):]
        return urllib.url2pathname(relative_url)

    def serve(self, request, path):
        from django.contrib.staticfiles import finders
        absolute_path = finders.find(path)
        if not absolute_path:
            raise Http404('%r could not be matched to a static file.' % path)
        absolute_path, filename = os.path.split(absolute_path)
        return serve(request, path=filename, document_root=absolute_path)
    def serve(self, request):
        """
        Actually serves the request path.
        """
        return serve(request, self.file_path(request.path), insecure=True)

    def __call__(self, environ, start_response):
        media_url_bits = urlparse(self.media_url)
        # Ignore all requests if the host is provided as part of the media_url.
        # Also ignore requests that aren't under the media path.
        if (media_url_bits[1] or
                not environ['PATH_INFO'].startswith(media_url_bits[2])):
            return self.application(environ, start_response)
        request = self.application.request_class(environ)
    def get_response(self, request):
        from django.http import Http404

        if self._should_handle(request.path):
            try:
            response = self.serve(request, self.file_path(environ['PATH_INFO']))
        except Http404:
            status = '404 NOT FOUND'
            start_response(status, {'Content-type': 'text/plain'}.items())
            return [str('Page not found: %s' % environ['PATH_INFO'])]
        status_text = STATUS_CODE_TEXT[response.status_code]
        status = '%s %s' % (response.status_code, status_text)
        response_headers = [(str(k), str(v)) for k, v in response.items()]
        for c in response.cookies.values():
            response_headers.append(('Set-Cookie', str(c.output(header=''))))
        start_response(status, response_headers)
        return response
                return self.serve(request)
            except Http404, e:
                if settings.DEBUG:
                    from django.views import debug
                    return debug.technical_404_response(request, e)
        return super(StaticFilesHandler, self).get_response(request)

    def __call__(self, environ, start_response):
        if not self._should_handle(environ['PATH_INFO']):
            return self.application(environ, start_response)
        return super(StaticFilesHandler, self).__call__(environ, start_response)
+4 −1
Original line number Diff line number Diff line
@@ -71,6 +71,9 @@ Type 'yes' to continue, or 'no' to cancel: """)
            if confirm != 'yes':
                raise CommandError("Static files build cancelled.")

        # Use ints for file times (ticket #14665)
        os.stat_float_times(False)

        for finder in finders.get_finders():
            for source, prefix, storage in finder.list(ignore_patterns):
                self.copy_file(source, prefix, storage, **options)
@@ -126,7 +129,7 @@ Type 'yes' to continue, or 'no' to cancel: """)
            else:
                destination_is_link = os.path.islink(
                    self.destination_storage.path(destination))
                if destination_last_modified == source_last_modified:
                if destination_last_modified >= source_last_modified:
                    if (not symlink and not destination_is_link):
                        if verbosity >= 2:
                            self.stdout.write("Skipping '%s' (not modified)\n"
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ class StaticFilesStorage(FileSystemStorage):
            raise ImproperlyConfigured("You're using the staticfiles app "
                "without having set the STATICFILES_URL setting. Set it to "
                "URL that handles the files served from STATICFILES_ROOT.")
        if settings.DEBUG:
            utils.check_settings()
        super(StaticFilesStorage, self).__init__(location, base_url, *args, **kwargs)


+5 −1
Original line number Diff line number Diff line
@@ -19,10 +19,14 @@ def staticfiles_urlpatterns(prefix=None):
        return []
    if prefix is None:
        prefix = settings.STATICFILES_URL
    if not prefix:
        raise ImproperlyConfigured(
            "The prefix for the 'staticfiles_urlpatterns' helper is empty. "
            "Make sure the STATICFILES_URL setting is set correctly.")
    if '://' in prefix:
        raise ImproperlyConfigured(
            "The STATICFILES_URL setting is a full URL, not a path and "
            "can't be used with the urls.staticfiles_urlpatterns() helper.")
            "can't be used with the 'staticfiles_urlpatterns' helper.")
    if prefix.startswith("/"):
        prefix = prefix[1:]
    return patterns('',
+15 −0
Original line number Diff line number Diff line
import fnmatch
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

def get_files(storage, ignore_patterns=[], location=''):
    """
@@ -28,3 +30,16 @@ def get_files(storage, ignore_patterns=[], location=''):
            dir = '/'.join([location, dir])
        static_files.extend(get_files(storage, ignore_patterns, dir))
    return static_files

def check_settings():
    """
    Checks if the MEDIA_(ROOT|URL) and STATICFILES_(ROOT|URL)
    settings have the same value.
    """
    if settings.MEDIA_URL == settings.STATICFILES_URL:
        raise ImproperlyConfigured("The MEDIA_URL and STATICFILES_URL "
                                   "settings must have individual values")
    if ((settings.MEDIA_ROOT and settings.STATICFILES_ROOT) and
            (settings.MEDIA_ROOT == settings.STATICFILES_ROOT)):
        raise ImproperlyConfigured("The MEDIA_ROOT and STATICFILES_ROOT "
                                   "settings must have individual values")
Loading