Is it possible to use flask to browse through a directory with files?
My code never seems to work correctly as weird appending between strings happens.
Also I don`t know how to implement a kind of check whether the path is a file or a folder.
Here is my Flask app.route:
#app.route('/files', defaults={'folder': None,'sub_folder': None}, methods=['GET'])
#app.route('/files/<folder>', defaults={'sub_folder': None}, methods=['GET'])
#app.route('/files/<folder>/<sub_folder>', methods=['GET'])
def files(folder,sub_folder):
basedir = 'files/'
directory = ''
if folder != None:
directory = directory + '/' + folder
if sub_folder != None:
directory = directory + '/' + sub_folder
files = os.listdir(basedir + directory)
return render_template('files.html',files=files,directory=basedir + directory,currdir=directory)
and here is my html template, if anyone could give me some pointers it would be greatly appreciated!
<body>
<h2>Files {{ currdir }}</h2> </br>
{% for name in files: %}
{{ name }} </br></br>
{% endfor %}
</body>s.html',files=files,directory=basedir + directory,currdir=directory)
A path converter (docs link) in the url structure is better than hardcoding all the different possible path structures.
os.path.exists can be used to check if the path is valid and os.path.isfile and os.path.isdir for checking if the path is a file or a directory, respectively.
Endpoint:
#app.route('/', defaults={'req_path': ''})
#app.route('/<path:req_path>')
def dir_listing(req_path):
BASE_DIR = '/Users/vivek/Desktop'
# Joining the base and the requested path
abs_path = os.path.join(BASE_DIR, req_path)
# Return 404 if path doesn't exist
if not os.path.exists(abs_path):
return abort(404)
# Check if path is a file and serve
if os.path.isfile(abs_path):
return send_file(abs_path)
# Show directory contents
files = os.listdir(abs_path)
return render_template('files.html', files=files)
Template (Now with directory browsing :) ):
<ul>
{% for file in files %}
<li>
<a href="{{ (request.path + '/' if request.path != '/' else '') + file }}">
{{ (request.path + '/' if request.path != '/' else '') + file }}
</a>
</li>
{% endfor %}
</ul>
Note: abort and send_file functions were imported from flask.
Here is a working example.
# app.py
from flask import Flask
from flask_autoindex import AutoIndex
app = Flask(__name__)
ppath = "/" # update your own parent directory here
app = Flask(__name__)
AutoIndex(app, browse_root=ppath)
if __name__ == "__main__":
app.run()
Here is a working repo
https://github.com/MrAmbiG/folderview
I created this function for my project ... it is working perfectly ... it start browsing at this folder /home/myuser/myfolder
#app.route('/myfolder/<path:folders>')
#app.route('/myfolder/')
def mybrowser(folders=''):
environ = flask.request.environ
path = environ.get('PATH_INFO')
path = path.lower()
#if path=='/myfolder': return flask.redirect(path+'/',code=307)
os_path = '/home/myuser'+path.rstrip('/')
if path.endswith('/'):
HTML_HEADER = """<html><head><title>Index of {path_title}</title></head><body bgcolor="white"><h1>Index of {path_title}</h1><hr><pre>../\n"""
HTML_FOOTER = "</pre><hr></body></html>"
path_title = os_path.split('myuser')[1]+'/'
html = HTML_HEADER.format(path_title=path_title)
import os,time
files = os.listdir(os_path)
for file in files:
path = os_path+'/'+file
size = str(os.path.getsize(path))
date = os.path.getmtime(path)
date = time.gmtime(date)
date = time.strftime('%d-%b-%Y %H:%M',date)
spaces1 = ' '*(50-len(file))
spaces2 = ' '*(20-len(size))
if os.path.isdir(path): html += '' + file + '/'+spaces1+date+spaces2+' -\n'
else: html += '' + file + ''+spaces1+' '+date+spaces2+size+'\n'
html += HTML_FOOTER
#open(os_path+'/index.html','w').write(html)
response_headers = {'Content-Type':'text/html','Content-Length':str(len(html))}
status = '200 OK'
response = flask.Response(html,status=status,headers=response_headers)
else:
response = flask.send_file(os_path,conditional=True)
return response
Here's a quick and dirty implementation using pathlib's .iterdir and Flask.send_from_directory to create dynamic routes to files in the same directory as this flask app and generates a unordered list of links to be displayed at the root route.
This isn't recursive. It won't create routes for sub-directories or files within subdirectories. It's what I needed when I came looking here on SO for answers.
"""Simple Flask App to serve the contents of the current directory.
$ python serve_directory.py
this serves browseable contents of this file's directory.
to http://localhost:8080.
"""
from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING
from flask import Flask, send_from_directory
if TYPE_CHECKING:
from typing import Iterator
from flask import Response
# Instantiate a Flask app object
app: Flask = Flask(__name__)
# Get the parent directory of this script. (Global)
DIR_PATH: Path = Path(__file__).parent
def get_files_from_this_directory() -> Iterator[str]:
"""Generate the items within this script's directory.
Yields:
Generator: item(s) in __file__'s directory.
"""
for dir_item in DIR_PATH.iterdir():
yield dir_item.name
#app.route("/files/<file_name>") # type: ignore
def serve_file(file_name: str) -> Response:
"""Set up a dynamic routes for directory items at /files/.
Args:
file_name (str): regular file.
Returns:
Response: regular file.
"""
return send_from_directory(DIR_PATH, file_name)
def html_ul_of_items() -> str:
"""Create a unordered list of anchors/links to file routes.
Returns:
str: a <ul> with N <li> elements where N is the number of
elements in __file__'s directory.
"""
html: str = "<ul>"
for dir_item in get_files_from_this_directory():
html += f"<li><a href='files/{dir_item}'>{dir_item}</a`></li>"
return f"{html}</ul>"
#app.route("/") # type: ignore
def serve_index() -> str:
"""Root route which displays an unordered list of directory items.
Returns:
str: a <ul> with N <li> elements where N is the number of
elements in __file__'s directory.
"""
return html_ul_of_items()
def main() -> None:
"""Run the flask app."""
app.run(port=8080)
if __name__ == "__main__":
main()
Related
I followed this tutorial and everything works except for downloading the images that were uploaded. I get 404 errors for everything I try to display in the browser. I can see the images on the hard drive just fine, but they do not download on the /uploads route. ANy ideas?
#bp.route('/uploads/<filename>')
def upload(filename):
print('path: '+str(current_app.config['PRODUCT_UPLOAD_PATH'])+', filename: '+filename)
return send_from_directory(current_app.config['PRODUCT_UPLOAD_PATH'], filename)
Here is the html template that loads the files. The filenames popup proeprly, but the route just shows 404 errors for all the images.
{% for file in files %}
<img src="{{ url_for('main.upload', filename=file) }}" style="width: 64px">
{% endfor %}
config.py to show where the directories are pointing.
MAX_CONTENT_LENGTH = 1024 * 1024
UPLOAD_EXTENSIONS = ['.jpg', '.png', '.gif']
PRODUCT_UPLOAD_PATH = 'uploads/products/'
Here is the solution I found that makes this work. Thanks for the help from everyone!
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
#This string does not work
#PRODUCT_UPLOAD_PATH = 'uploads/products/'
#This is the proper way to configure file paths
PRODUCT_UPLOAD_PATH = os.path.join(basedir, 'uploads', 'products')
is there a posibility to create an easy function like
def createPath(name):
path = "abcd.jpg"
finalPath = name + "/" + path
return finalPath
(...)
path = createPath("folder1")
return render_template('index.html', PATH=path)
and use the returned finalPath in a html file like
<img src=" {{PATH}} " alt="Trulli" width="500" height="333">
It does not work.
I don't know how to use variables in html.
Thank you a lot
By any chance, are you sure your url name + "/" + path is served by a web server ? If you want to serve static file you can have a look at https://flask.palletsprojects.com/en/1.1.x/tutorial/static/
This works for me :
from flask import Flask,render_template_string
app = Flask(__name__)
#app.route("/", methods=["GET"])
def hello_world():
name = "flask-logo.png"
path = createPath(name)
return render_template_string("""<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body>
<h1>Hello World</h1>
<img src="{{PATH}}" alt="Trulli" width="500" height="333">
</body>
</html>
""",PATH=path)
def createPath(name):
path = "https://flask.palletsprojects.com/en/1.1.x/_images"
finalPath = path + "/" + name
return finalPath
if __name__ == '__main__':
app.run()
My images of plots won't display. I store them separately in "uploads" directory (not static nor its sub).
#app.route('/job/<job_id>')
def get_job(job_id):
directory_name = db.get(job_id)
if directory_name is False:
abort(404)
return render_template('job.html', directory_name=directory_name)
Im passing directory_name to the html:
<html>
<body>
<img src="{{url_for('send_image', directory_name=directory_name)}}" >
</body>
</html>
Which refers to other view that should browse my directories.
#app.route('/uploads/<directory_name>/plot.png')
def send_image(directory_name, job_id):
return send_from_directory("uploads", directory_name + "plot.png")
However i still get nothing. What I am doing wrong? Is "static" the only directory that flask can handle?
This question already has answers here:
How to serve static files in Flask
(24 answers)
Closed 5 years ago.
I'm making an upload/download service just for fun but am struggling to serve files that are outside of static directory, which causes an issue because anyone could visit www.mysite.com/static and view the contents.
This is what I have so far. Forgive the ugly paths of my network storage :)
if not os.path.exists('\\ATTILA\\Development\\GIT\\MyCloud\\static\\'+ session['username']):
os.makedirs('\\\\ATTILA\\Development\\GIT\\MyCloud\\static\\'+ session['username'])
#Download links for all files
pathing = []
my_path = '\\\\ATTILA\\Development\\GIT\\MyCloud\\static\\'+ session['username'] + '\\'
os.chdir('\\\\ATTILA\\Development\\GIT\\MyCloud\\static\\'+ session['username'])
for myfile in glob.glob('*'):
downs = my_path + myfile
pathing.append(tuple([downs, myfile]))
In my template I have a simple for loop
{% for myfile, name in pathing %}
<a href='{{ myfile }}' download>{{ name }}</a><br>
{% endfor %}
So my view looks like this:
As it stands my files are downloadable, however if I change the file paths for the downloads to a folder outside of 'static' then instead of download links I get 404 errors that point to the URL + the file path like so www.mysite.com\ATTILLA\Development\some_other_folder any suggestions?
If you want place your app in production you need use solutions like a nginx for serving you static files.
Usually in development stage Flask work with regulary static files (css, js and another) self. It's normal.
If you want hide some private data or uploaded files you need use something like this:
from flask import Flask, make_response
...
#app.route('/file_downloads/<filename>')
def file_downloads(filename):
headers = {"Content-Disposition": "attachment; filename=%s" % filename}
with open('../tmp/you_private_file.zip', 'r') as f:
body = f.read()
return make_response((body, headers))
i am creating pdf from html and it gets converted but without image. i have tried the absolute urls also but it still doesn't work
pdf function:
def test_pdf(request):
template = get_template('../templates/index.html')
html = template.render(Context(data))
filename = 'pdfs/'+str(random.random())+'.pdf'
file = open(filename, "w+b")
pisaStatus = pisa.CreatePDF(html.encode('utf-8'), dest=file, encoding='utf-8',link_callback=link_callback)
# Return PDF document through a Django HTTP response
file.seek(0)
pdf = file.read()
file.close() # Don't forget to close the file handle
return HttpResponse({"success":"success"})
def link_callback(uri, rel):
sUrl = settings.STATIC_URL # Typically /static/
sRoot = settings.STATIC_ROOT # Typically /home/userX/project_static/
mUrl = settings.MEDIA_URL # Typically /static/media/
mRoot = settings.MEDIA_ROOT # Typically /home/userX/project_static/media/
if uri.startswith(mUrl):
path = os.path.join(mRoot, uri.replace(mUrl, ""))
elif uri.startswith(sUrl):
path = os.path.join(sRoot, uri.replace(sUrl, ""))
else:
return uri # handle absolute uri (ie: http://some.tld/foo.png)
if not os.path.isfile(path):
raise Exception(
'media URI must start with %s or %s' % (sUrl, mUrl)
)
return path
settings file :
PROJECT_ROOT = "/var/www/html/newclone/userapi/"
MEDIA_ROOT = path.join(PROJECT_ROOT,'media')
MEDIA_URL = '/media/'
STATIC_ROOT = path.join(PROJECT_ROOT,'static-root')
STATIC_URL = "/static/"
What is wrong in this. pdf is generated successfully but the images are missing
html file :
<div class="h1"><img src="/media/xyz"></div>
Could not even imagine the error :
in my css i have written :
.main{width:75%;}
because of this images were not visible. I just removed it randomly and images started displaying