views and functions for serving static files these are only to be used during development and should not be used in a production setting return a path to a builtin template avoid calling this function at the module level or in a classdefinition because file may not exist e g in frozen environments serve static files below a given point in the directory structure to use put a url pattern such as from django views static import serve path path path serve documentroot pathtomyfiles in your urlconf you must provide the documentroot param you may also set showindexes to true if you d like to serve a basic index of the directory this index view will use the template hardcoded below but if you d like to override it you can create a template called staticdirectoryindex html respect the ifmodifiedsince header translatable string for static directory index template title was something modified since the user last downloaded it header this is the value of the ifmodifiedsince header if this is none i ll just return true mtime this is the modification time of the item we re talking about return a path to a builtin template avoid calling this function at the module level or in a class definition because __file__ may not exist e g in frozen environments serve static files below a given point in the directory structure to use put a url pattern such as from django views static import serve path path path serve document_root path to my files in your urlconf you must provide the document_root param you may also set show_indexes to true if you d like to serve a basic index of the directory this index view will use the template hardcoded below but if you d like to override it you can create a template called static directory_index html respect the if modified since header translatable string for static directory index template title was something modified since the user last downloaded it header this is the value of the if modified since header if this is none i ll just return true mtime this is the modification time of the item we re talking about
import mimetypes
import posixpath
from pathlib import Path

from django.http import FileResponse, Http404, HttpResponse, HttpResponseNotModified
from django.template import Context, Engine, TemplateDoesNotExist, loader
from django.utils._os import safe_join
from django.utils.http import http_date, parse_http_date
from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy


def builtin_template_path(name):
    
    return Path(__file__).parent / "templates" / name


def serve(request, path, document_root=None, show_indexes=False):
    
    path = posixpath.normpath(path).lstrip("/")
    fullpath = Path(safe_join(document_root, path))
    if fullpath.is_dir():
        if show_indexes:
            return directory_index(path, fullpath)
        raise Http404(_("Directory indexes are not allowed here."))
    if not fullpath.exists():
        raise Http404(_("“%(path)s” does not exist") % {"path": fullpath})
    
    statobj = fullpath.stat()
    if not was_modified_since(
        request.META.get("HTTP_IF_MODIFIED_SINCE"), statobj.st_mtime
    ):
        return HttpResponseNotModified()
    content_type, encoding = mimetypes.guess_type(str(fullpath))
    content_type = content_type or "application/octet-stream"
    response = FileResponse(fullpath.open("rb"), content_type=content_type)
    response.headers["Last-Modified"] = http_date(statobj.st_mtime)
    if encoding:
        response.headers["Content-Encoding"] = encoding
    return response



template_translatable = gettext_lazy("Index of %(directory)s")


def directory_index(path, fullpath):
    try:
        t = loader.select_template(
            [
                "static/directory_index.html",
                "static/directory_index",
            ]
        )
    except TemplateDoesNotExist:
        with builtin_template_path("directory_index.html").open(encoding="utf-8") as fh:
            t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string(
                fh.read()
            )
        c = Context()
    else:
        c = {}
    files = []
    for f in fullpath.iterdir():
        if not f.name.startswith("."):
            url = str(f.relative_to(fullpath))
            if f.is_dir():
                url += "/"
            files.append(url)
    c.update(
        {
            "directory": path + "/",
            "file_list": files,
        }
    )
    return HttpResponse(t.render(c))


def was_modified_since(header=None, mtime=0):
    
    try:
        if header is None:
            raise ValueError
        header_mtime = parse_http_date(header)
        if int(mtime) > header_mtime:
            raise ValueError
    except (ValueError, OverflowError):
        return True
    return False