title: Serving and opening directories with Python, Flask & Jinja
body: <p>I have searched but could not find an answer. </p>
  
  <p>Im new to python, 1 week exactly, and i'm using python with Flask to serve a web directory containing files and folders.</p>
  
  <p>I can download files, but get a 404 when trying to open a directory. Can you help.</p>
  
  <p>views.py:</p>
  
  <pre><code>from flask import Flask, render_template, send_from_directory, send_file
  #from app import app
  import os
  from pprint import pprint
  import magic
  import urllib
  import sys
  
  reload(sys)
  sys.setdefaultencoding('utf8')
  
  app = Flask(__name__)
  mime = magic.Magic(mime=True)
  
  """
  Config
  """
  # To list the current directory
  #base_directory = os.path.dirname(os.path.abspath(__file__))
  base_directory = "/var/www/html/test"
  # directories not to be listed
  ignored_dirs = ["venv"]
  ignore_dotfiles = True  
  ignore_dollarfiles = True
  omit_folders = False
  omit_files = False
  
  """ The base route with the file list """
  @app.route("/")
  def home():
      files = []
      dirs = []
  
      meta = {
          "current_directory": base_directory
      }
  
      for (dirpath, dirnames, filenames) in os.walk(base_directory):
              for name in filenames:
              if omit_files == True:
                  break
  
              for ign in ignored_dirs:
                  if ign in dirnames:
                      dirnames.remove(ign)
  
              nm = os.path.join(dirpath, name).replace(base_directory, "").strip("/").split("/")
              fullpath = os.path.join(dirpath, name)
  
              if os.path.isfile(fullpath) == False:
                  continue
  
              size = os.stat(fullpath).st_size
  
              if len(nm) == 1:
                  name_s = name.split(".")
                  if ignore_dotfiles == True:
                      if name_s[0] == "" or name_s[0] == None:
                          continue
  
                  files.append({
                      "name": name,
                      "size": str(size) + " B",
  #                       "mime": mime.from_file(fullpath),
                      "fullname": urllib.quote_plus(fullpath)
                  })
  
          for dirname in dirnames:
              if omit_folders == True:
                  break
  
              fullpath = os.path.join(dirpath, dirname)
  
              if ignore_dotfiles == True:
                  name_split = dirname.split(".")
                  if name_split[0] == "" or name_split[0] == None:
                      continue
  
              if ignore_dollarfiles == True:
                  name_split = dirname.split("$")
                  if name_split[0] == "" or name_split[0] == None:
                      continue
  
              dirs.append({
                  "name": dirname,
                  "size": "/",
  #                   "mime": mime.from_file(fullpath)
              })
  
      return render_template("index.html", files=sorted(files, key=lambda k: k["name"].lower()), folders=dirs, meta=meta)
  
  @app.route("/download/&lt;filename&gt;")
  def download(filename):
      filename = urllib.unquote(filename)
      if os.path.isfile(filename):
          if os.path.dirname(filename) == base_directory.rstrip("/"):
              return send_file(filename, as_attachment=True)
              else:
              return render_template("no_permission.html")
      else:
              return render_template("not_found.html")
      return None
  
  if __name__ == "__main__":
      app.run(host="0.0.0.0", debug=True)
  </code></pre>
  
  <p>templates/index.html:</p>
  
  <pre><code>{% extends "_layout.html" %}
  {% block content %}
  
  &lt;div class="container" style="margin-top: 10px"&gt;
      &lt;div class="row"&gt;
      &lt;div class="col-lg-12"&gt;
      &lt;div class="card"&gt;
          &lt;div class="card-header"&gt;Directory listing for "{{meta.current_directory}}"&lt;/div&gt;
              &lt;div class="card-block"&gt;
                  &lt;table class="table"&gt;
                  &lt;thead&gt;
                      &lt;tr&gt;
                          &lt;th&gt;Name&lt;/th&gt;
                          &lt;th&gt;Size&lt;/th&gt;
  &lt;!--                        &lt;th&gt;MIME&lt;/th&gt; --&gt;
                          &lt;th&gt;Download&lt;/th&gt;
                      &lt;/tr&gt;
                  &lt;/thead&gt;
                  &lt;tbody&gt;
                      {% for folder in folders %}
                      &lt;tr&gt;
                          &lt;td&gt;&lt;a href="{{meta.current_directory}}{{ folder.fullname|urlencode }}/{{folder.name}}"&gt;&lt;i class="fa fa-file-o"&gt;&lt;/i&gt; {{ folder.name }}&lt;/a&gt;&lt;/td&gt;
                          &lt;td&gt;{{ folder.size }}&lt;/td&gt;
  &lt;!--                        &lt;td&gt;&lt;span class="label label-primary"&gt;{{ folder.mime }}&lt;/span&gt;&lt;/td&gt; --&gt;
                          &lt;td&gt;&lt;/td&gt;
                      &lt;/tr&gt;
                      {% endfor %}
  
                      {% for file in files %}
                      &lt;tr&gt;
                          &lt;td&gt;&lt;i class="fa fa-file-o"&gt;&lt;/i&gt; {{ file.name }}&lt;/td&gt;
                          &lt;td&gt;{{ file.size }}&lt;/td&gt;
  &lt;!--                        &lt;td&gt;&lt;span class="label label-primary"&gt;{{ file.mime }}&lt;/span&gt;&lt;/td&gt; --&gt;
                          &lt;td&gt;&lt;a href="download/{{ file.fullname|urlencode }}" class="label label-success"&gt;&lt;i class="fa fa-download"&gt;&lt;/i&gt; Download&lt;/a&gt;                &lt;/td&gt;
                      &lt;/tr&gt;
                      {% endfor %}
                  &lt;/tbody&gt;
                  &lt;/table&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
      &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  {% endblock %}
  </code></pre>