How can I preview an image to be uploaded in flask? - python

I am trying to preview an image to be uploaded. I am using an upload form shown here
class Upload_Form(Form):
date = DateField('Date on Certificate', validators =...)
image = FileField(validators=[DataRequired()])
All that is really important for this is the image FileField. Here is the associated html with the upload. It extends a base html
{% block content %}
<form action="" method="POST" name="upload" enctype="...">
<p>{{ form.image.label }}<br>{{ form.image }}</p>
...
{% endblock %}
I need to either use python flask to preview the image or find a way to pull the URL from the file in the FileField to display the image with JS. I have tried form.image.url but that just returns an empty string. I know how to do this in JavaScript but I am having trouble understanding how to get it to be stored in the database since I am using a Python flask framework and it needs to be passed in the FileField from the class Upload_Form. I'm just having a hard time translating this to python flask as opposed to JS. Here is where I extract the file in flask.
#app.route('/upload', methods=['GET', 'POST'])
def upload():
form = Upload_Form()
if request.method == "POST" and form.validate_on_submit():
if img and os.path.splitext(img.filename)[1] in ALLOWED_EXTENSIONS:
try:
div_id = Division.query.filter_by(category=form.category.data).first().id
except AttributeError:
div_id = None
c = Certificate(div_id=div_id,user_id=g.user.id, status=False)
db.session.add(c)
db.session.commit()
...
return render_template('upload.html', title='Upload successful', form=form)

Related

Flask app gives a 500 (internal server error) page (without any error traceback) when trying to upload an image. What am I doing wrong?

I'm currently trying to build a flask app which will accept an uploaded image, allow the user to apply filters to that image, and then let the user view their library of uploaded and filtered images. I have a method called upload(), and a template upload.html, which are printed in the code snippets below - I have tried three different versions of upload() based on tutorials for uploading images in flask, and each of them have the same result. The upload template with the form loads normally, I upload an image, and then I get an internal server error. I go back to the terminal in my IDE (I'm using the CS50 IDE) to check where the error came from, and there is no traceback whatsoever.
What's weird is that I've based the second and third attempts at implementing this on tutorials I've seen, in which the exact same implementation worked just fine.
Here is the HTML template:
{% extends "layout.html" %}
{% block title %}
Upload
{% endblock %}
{% block main %}
<form action="/upload" method="post" enctype=multipart/form-data>
<input type="file" name="image">
<input type="submit" value="Upload">
</form>
{% endblock %}
The first version of upload():
#app.route("/upload", methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template("upload.html")
if request.files:
#The POST request came through with an image file.
image = request.files['image']
if image.filename == "":
print("No filename")
return redirect("/upload")
if image and allowed_image(image.filename):
filename = secure_filename(image.filename)
image.save(os.path.join(app.config['IMAGE_UPLOADS'], filename))
print("Image saved.")
return redirect("/")
else:
print("That file extension is not allowed")
return redirect("/upload")
else:
print("Not request.files")
return render_template("upload.html")
The second, for which photos = UploadSet('photos', IMAGES), using the flask_uploads extension:
#app.route("/upload", methods=['GET', 'POST'])
def upload():
if request.method == 'POST' and 'photo' in request.files:
filename = photos.save(request.files['photo'])
print(filename)
return redirect("/")
return render_template('upload.html')
And the third:
def upload():
if request.method == 'POST':
target = os.path.join(APP_ROOT, "images/")
print(target)
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist("image"):
print(file)
filename = file.filename
destination = "/".join([target, filename])
print(destination)
file.save(destination)
return render_template("index.html")
else:
return render_template("upload.html")
Here's an image of the upload screen
The Internal Server Error
It is very easy to upload files with flask_uploads [pip install flask_uploads]. With that, you don't have to write boilerplate code for uploading files. NOTE - You might have to install specific version of werkzeug as pip install werkzeug==0.16.0 in case you face problem as 'cannot import name 'secure_filename' from 'werkzeug''
Here is an example I found on GitHub.
https://gist.github.com/greyli/addff01c19ddca78cddf386800e57045

Python - Django 2.0 - URL patterns, passing arguments

I am writing a very basic web page in Python which has a text box where a user can type in a username, then hit the Ok button which submits a form using a GET request. The GET passes the username as an argument and searches the auth_user table in the database.
My problem is I am not able to pass the username argument, please help if you can Django 2.0 url patterns
urls.py
app_name = 'just_gains'
urlpatterns = [
path('lifecoaching', views.LifeCoach, name='life_coaching'),
path('lifecoaching/resultslifecoaching/<str:user_name>', views.LifeCoachSearchResults, name='results_life_coaching'),
]
forms.py
class LifeCoachSearch(forms.Form):
user_name = forms.CharField(label='Username', max_length=100, required = False)
views.py
def LifeCoach(request):
if request == 'GET':
form = LifeCoachSearch(request.GET)
if form.is_valid:
user_name = form.cleaned_data['user_name']
LifeCoachSearchResults(request,user_name)
else:
form = LifeCoachSearch()
return render(request, 'just_gains/life_coaching.html', {'form': form})
def LifeCoachSearchResults(request, user_name):
testUser = User.objects.filter(username__startswith=user_name)
context = {'TestUser': testUser}
return render(request, 'just_gains/results_life_coaching.html', context)
HTML (lifecoaching)
<form action="{% url 'just_gains:results_life_coaching' %}" method="GET" >
{% csrf_token %}
{{ form }}
<input type="submit" value="OK">
</form>
HTML (resultslifecoaching)
<ul>
<li><a>print usernames that match the argument</a></li>
</ul>
Forgive me for the short response as I am on mobile. Try passing your username as a string in the path using <str:user_name>
Usually I think the form should submit via POST rather than GET, and the value of the submitted username would then be available in the dictionary request.POST['username']. GET should be used to get forms from the server; POST posts information back to the server. POST ensures that the browser bundles everything in the form and sends it complete, but GET tries to encode it in the URL and makes no guarantees.
Using forms, its helpful to have the View divide so that GET requests pull up blank or prepopulated forms (the empty search box) and POST requests are processed and redirected to the parameterized results screen you have.
You would then create a httpRedirect to re-assign the request to your URL with a parameter. I think this link, example 2 is the right way to go.
https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#redirect
So your function would look like:
def LifeCoach(request):
if request.method = 'GET':
return render(request, 'just_gains/life_coaching.html', context)
elif request.method = 'POST':
# I have skipped form validation here for brevity
return redirect('results_life_coaching',request.POST['username'])
It's possible that having a field called username may clash with or confuse you later when using request.USER['username']. Don't forget to change your form html! All the best!
[Edit 1] My code was wrong; GET should call the lifecoaching form, POST should redirect to the results_life_coaching page.
[Edit 2] My suggestions for your templates:
HTML (lifecoaching.html)
<form action="{% url 'just_gains:life_coaching' %}" method="POST" >
{% csrf_token %}
{{ form }}
<input type="submit" value="OK">
</form>
HTML (resultslifecoaching.html)
<ul>
{% for item in username_list %}
<li>{{item.user_name}} - {{item.achievement}} </li>
{% endfor %}
</ul>

How to return data from a table in a Django template

I am trying to display data from a website in HTML.
I have created a class called Video in models.py as follows:
class Video(models.Model):
filename = models.CharField("File Name", max_length=100)
title = models.CharField("Video Title", max_length=250)
The database is migrated and I am able to insert data into it using a Django form. I have checked and there is data in the database.
I have the following code in my HTML template file, but the page is empty when it is displayed, and is showing no data.
{% for video in Video %}
<div class="row">
<div class="col-md-3">
{{ video.title }}
</div>
</div>
{% endfor %}
Why isn't this displaying any data in the rendered HTML page?
Edit:
This is the relevant code from the view:
def listvideos(request):
"""Renders the listvideos page."""
assert isinstance(request, HttpRequest)
return render(
request,
'app/listvideos.html',
)
Templates can only render what you pass to them. You're not sending anything called Video, so you can't iterate over it.
return render(
request,
'app/listvideos.html',
{'Video': Video.objects.all()}
)
You should consider whether you really want to call your parameter Video, though; it should probably be called videos both here and in the template.
(And please remove that assertion. For a start, it has no place in production code; and secondly the request will always be an HttpRequest, that is part of the contract for a view.)

Bad Request(400) when upload file, Flask

I'm trying to do a file upload to my Flask backend
My Python code
#app.route('/new_upload/', methods=['GET', 'POST'])
#login_required
def upload_file():
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
flash("File uploaded: Thanks!", "success")
return redirect(url_for('upload.html'))
return render_template('upload.html', filename=filename)
My HTML looks like this:
{% extends "layout.html" %}
{% from "macros.html" import render_field %}
{% block content %}
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
{% endblock %}
In home page when I clicked on upload file link browser show me
Bad Request
The browser (or proxy) sent a request that this server could not
understand.
For clearance Home page HTML and image are attached bellow
<div class="main">
<nav>
All
{% if current_user.is_authenticated %}
Following
Create New Post
Upload file
{% endif %}
</nav>
{% block content %}{% endblock %}
</div>
Home Page
After click
Please try help me, I am just learning
In this piece of code
return redirect(url_for('upload.html'))
You should change url_for('upload.html') to url_for('upload') or what is suppose to be the name of the function instead of the html template.
Also if you are about to use the same function "def upload_file()" for HTTP GET and HTTP POST requests, then you should specify the piece of code that would be executed on post and another piece that would be executed when only GET request is performed. Something like:
# Import request if you haven't.
from flask import request
#app.route('/new_upload', methods=['GET', 'POST'])
#login_required
def upload_file():
if request.method == 'POST':
# This will be executed on POST request.
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
flash("File uploaded: Thanks!", "success")
return redirect(url_for('upload_file'))
# This will be executed on GET request.
return render_template('upload.html')
I haven't tested the above code, but this should be the approach if you use one function for GET and POST http request.
If you do not differentiate the upload functionality (on POST HTTP request) and rendering the template (on GET request) it would try to execute all the code on every request and would fall in loop where would return redirect(url_for('upload_file')) every time and would not get to the return render_template('upload.html') where is suppose to show you page (HTTP request with code 200 instead of code 400).
You can strictly follow this example:
http://flask.pocoo.org/docs/0.10/patterns/fileuploads/ to get the overal idea.
You can also have a look at the HTTP Methods: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods so you would have better overview what is POST and GET request.

Python Flask get item from HTML select form

Im having trouble getting anything from the shown HTML form
I always get "ValueError: View function did not return a response"
Can somebody help me out here please? I have tried every variation of request.get that I can find on the web. Also if I specify my form should use post it uses get anyway - anybody know why this is?
Im new to flask so forgive my ignorance!
Thanks in advance.
The python file (routes.py)
from flask import Flask, render_template, request
import os
app = Flask(__name__)
musicpath = os.listdir(r"C:\Users\Oscar\Music\iTunes\iTunes Media\Music")
lsize = str(len(musicpath))
looper = len(musicpath)
#app.route('/')
def home():
return render_template('home.html', lsize=20, looper=looper, musicpath=musicpath)
#app.route('/pop', methods=['POST', 'GET'])
def pop():
if request.method == "GET":
text = request.args.get('som')
return text
#Have tried every variation of request.get
#app.route('/about')
def about():
name = "Hello!"
return render_template('about.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
The html file (home.html)
{% extends "layout.html" %}
{% block content %}
<div class="jumbo">
<h2>A Music app!<h2>
</div>
<div>
{% if lsize %}
<form action="/pop">
<select id="som" size="20">
{% for i in range(looper):%}
<option value="{{i}}">{{ musicpath[i] }}</option>
{% endfor %}
</select>
</form>
{% endif %}
</div>
Select,
{% endblock %}
The Problem is that your HTML form does not have a name.
request.args.get("som") needs an HTML form input with the name "som"
<select name="som" id="som" size="20">
Just change that line and add a name. The form is not interested in the id attribute.
You don't specified the method of the form, you have to do it! For example use this<form method="POST action"/pop">
Your form action is /pop. That means that if you submit the form it will do a POST request to the address /pop. Your code does only return a value for a GET request, therefore Flask complains you do not return anything. Write some code to process a POST request and return a text or rendered template.
BTW, in the code for GET you refer to request.args.get('som'); this gives you request arguments (i.e. in the URL), not from the form. som is in the form, so you cannot refer to it this way.

Categories