File is empty after saving flask uploads - html

I've been trying to upload a file using Flask and HTML forms. Now I can save an uploaded file but it shows up empty (0 bytes). After that I store the form entries in a database.
So im stuck at saving the file.
This is the python code
#app.route('/handle_data', methods=['POST'])
def handle_data():
naam = request.form['naam']
leeftijd = request.form['leeftijd']
gewicht = request.form['gewicht']
geslacht = request.form['geslacht']
filename = "x"
if request.method == 'POST' and 'photo' in request.files:
filename = photos.save(request.files['photo'])
photos.save(request.files['photo'], opslag)
cur = mysql.connect()
cursor = cur.cursor()
cursor.execute("INSERT INTO gekko (naam, leeftijd, gewicht, geslacht, foto) VALUES (%s, %s, %s, %s, %s)", (naam, leeftijd, gewicht, geslacht, filename))
# cursor.execute("INSERT INTO gekko (naam, leeftijd, gewicht) VALUES (" + str(naam) + "," + leeftijd + "," + gewicht + ")")
cur.commit()
cursor.close()
cur.close()
return "added"
HTML form:
{% extends "base.html" %}
{% block body %}
<form action="{{ url_for('handle_data') }}" enctype=multipart/form-data
method="POST">
Naam van de gekko:<br>
<input type="text" name="naam">
<br>
Leeftijd van de gekko:<br>
<input type="text" name="leeftijd">
<br>
Gewicht van de gekko:<br>
<input type="text" name="gewicht">
<br>
Geslacht van de gekko:<br>
<input type="radio" name="geslacht" value="man"> Man
<input type="radio" name="geslacht" value="vrouw"> Vrouw<br>
<br>
<input type="file" id="photo" name="photo">
<br>
<input type="submit" value="Submit">
</form>
{% endblock %}

We don't really know what the class photos is, nor what it's method save does, but that's where the error is probably occurring.
Try this instead:
request.files['photo'].save('test.jpg')

I realized that flask has a habit of including one empty file upload with the exact same name and details as one of the file attachments(usually the first attachment) WHEN you use the 'multiple' attribute in your form.
My workaround was to
create a temporary random filename and save the file upload
use os.stat(temp_filename).st_size to check if the file is empty
if the file is empty, delete it with os.remove, otherwise, rename the file to your preferred [secure] filename
an example...
# ...
def upload_file(req):
if req.method != 'POST': return
# file with 'multiple' attribute is 'uploads'
files = req.files.getlist("uploads")
# get other single file attachments
if req.files:
for f in req.files: files.append(req.files[f])
for f in files:
if not f.filename: continue
tmp_fname = YOUR_TEMPORARY_FILENAME
while os.path.isfile(tmp_fname):
# you can never rule out the possibility of similar random
# names
tmp_fname = NEW_TEMPORARY_FILENAME
# TEMP_FPATH is he root temporary directory
f.save(os.path.join(TEMP_FPATH, tmp_fname))
# and here comes the trick
if os.stat(os.path.join(TEMP_FPATH, tmp_fname)).st_size:
os.system("mv \"{}\" \"{}\" > /dev/null 2> /dev/null".format(
os.path.join(TEMP_FPATH, tmp_fname),
os.path.join(ACTUAL_FILEPATH, f.filename))
))
else:
# cleanup
os.remove(os.path.join(TEMP_FPATH, tmp_fname))
pass
#app.route("/upload", methods=["POST"])
def upload():
upload_files(request)
return "files are uploaded!"
# ...

Related

facing problems in uploading files to a particular directory

i am using a html template to upload a file but i don't know how to process that file in django views file
i also have a model which is connected with the database
here is my html file
{% extends 'base.html' %}
{% block body %}
<form action="file" method="post" enctype="multipart/form-data" >
{% csrf_token %}
<input type="text" name="userName" placeholder="username">
<input name="file" type="file">
<input type="submit" value="submit">
</form>
{% for message in messages %}
{{ message }}
{%endfor%}
{% endblock %}
and here is my views.py function
def File(request):
if request.user.is_authenticated:
if request.method == 'POST':
user = request.POST['userName']
file = request.FILES
print(file)
# file = request.POST.copy()
# file.update(request.FILES)
# content_type = copied_data['file'].get('content-type')
# path = os.path.join(r'C:\Users\harsh\PycharmProjects\swatchBharat\SwatchBharat\media\files\\',file)
if User.objects.filter(username=user).exists():
file2 = points()
file_obj1 = DjangoFile(open(file, mode='rb'), name=file)
file_obj = File.objects.create(title=file, file=file_obj1, content_object=file, author=file.client)
file2.file =file2.save(ContentFile(file_obj))
file2.user = user
file2.save()
return HttpResponse('sucess bale bale!!!!!!!')
else:
messages.info(request,'the username you entered is incorrect')
return redirect("file")
return render(request, 'file.html')
else:
return HttpResponse('sorry this is restricted, login to continue')
my model.py file
from django.db import models
# Create your models here.
class points(models.Model):
user = models.TextField(max_length=50,default=None)
file = models.FileField(upload_to='files/')
point_3 = models.BooleanField(default=False)
point_5 = models.BooleanField(default=False)
point_9 = models.BooleanField(default=False)
i am stuck with it pls someone help me out
the solution for this is simple , thanks to shivendra-pratap-kushwaha for documentation link - docs.djangoproject.com/en/3.2/topics/http/file-uploads this was really helpfull
just need to specify request.FILES['file'] instead of request.FILES

How to send a string from python to HTML element using Flask

How to send a sting text data from a python script to a specific HTML element. So that I can display it to users clearly and in a certain place using Flask Python library.
python script
#app.route('/services', methods=['POST', 'GET'])
def upload_image():
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No image selected for uploading')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
full_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(full_path)
# print('upload_image filename: ' + filename)
flash('Image successfully uploaded and displayed')
get_image(file.filename)
get_image_path()
data = 'render some text sting here'
print(data)
return render_template('services.html', filename=filename, dataToRender=data)
else:
flash('Allowed image types are -> png, jpg, jpeg, gif')
return redirect(request.url)
HTML
<form method="post" action="{{ url_for('upload_image') }}" enctype="multipart/form-data">
<label for="img" style="margin-bottom: 40px;font-size: 30px">choose image:</label>
<input type="file" onchange="preview(event)" autocomplete="off" required name="file"><br>
<img class="card-img-top" src="img/inttion.jpg" id="imgg" alt="Card image cap">
<p>
<input type="submit" value="Submit">
<h3>Your Recognition Result IS</h3>
<input type="text" name="result">
<h1>here is the result {{ dataToRender }}</h1>
</p>
</form>
To do what you are asking, you will have to make use of flask's ability to integrate with a templating engine (flask uses Jinja2 by default). This would look something like this:
In your main file with your routes in it, you will have to define a route on which you want to render a template
from flask import render_template
#app.route('/')
def index():
data = someFunction()
return render_template('index.html', dataToRender=data)
In another file called templates/index.html you will have to define the template and this is where you can dictate where the information that you provided will show up.
<!DOCTYPE html>
<title>Hello from Flask</title>
<h1>Hello {{ dataToRender }}!</h1>
I hope this helps. Flask also has some great documentation on the subject that can be found here

add value to new table in mysql

I have a database on flask mysql and user can login to profile page. I need to add description text, but it does not insert into database. What can be the problem?
app.py
#app.route('/profile', methods=['GET','POST'])
def profile():
if 'loggedin' in session:
return render_template('profile.html', id=session['id'], email=session['email'])
if request.method == 'POST':
texts = request.form['text']
cur = mysql.connection.cursor()
cur.execute('INSERT INTO users.data(texts) VALUES (%s)', (texts))
mysql.connection.commit()
cur.close()
return render_template('profile.html', texts=texts)
return redirect(url_for('login'))
profile.html
your id is: {{ id }}
your email is: {{ email }}
your text is: {{ texts }}
<form action="" method="post">
<input type="text" class="searchTerm" name="text" placeholder="Add your symptoms">
<button type="submit" value="submit" class="searchButton" name=form>
<span class="submit-symp">Submit</span>
</button>
</form>
id and email appear but I can not add data to new column and get it back from db.
python requires a tuple with two elements, even when one is empty
cur.execute('INSERT INTO users.data(texts) VALUES (%s)', (texts,))
O would test the sql command in mysql workbench and test it, depending on the table designb that could fail
IO think you wnat tgo update
cur.execute('UPDATE users.data SET texts = %s WHERE id = ?', (texts,session['id']))

how to display uploaded file size in need for minimal file upload django example

i needed to display file size in my html code along with changes in views and models.please help me to do this.
views.py
this is my view code.changes to display file size when it is uploaded
def index(request):
response = TemplateResponse(request, 'login.html', {})
return response
def login(request, username, password):
user = username[:-1]
for i in AppUser.objects.all():
if ( user == i.username and password == i.password ):
return list(request)
else:
return index(request)
def list(request):
# Handle file upload
print "im getting in"
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'],created_at = datetime.datetime.now())
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('cloudStorageManager.views.list'))
else:
print "else"
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response('list.html',{'documents': documents, 'form': form, 'created_at': datetime.datetime.now()},context_instance=RequestContext(request))
models.py
attribute for displaying file size
class Document(models.Model):
docfile = models.FileField(upload_to='documents')
created_at=models.DateTimeField(auto_now_add=True , blank=True)
list.html
html code to display the file size while uploading
{% for document in documents %}
<tr>
<td>
<input type="checkbox" class="case" id="chk{{forloop.counter}}" value="{{ document.docfile.name }}">
</td>
<td>{{ document.docfile.name }} {{ document.created_at }}</td>
<td><button class="btn btn-success btn-flat"><span class="glyphicon glyphicon-cloud-download"> </span> Download</button></td>
<td>
{{ document.docfile.size |filesizeformat}}
Docs for File size. Docs for filesizeformat filter.
You can know the size and validate the uploaded files in your forms.py file.
class DOcumentForm(...):
...
docfile = forms.FileField(...)
...
def clean_docfile(self):
current_size = self.cleaned_data['docfile'].size
if current_size < 2621440 # size in bytes:
return self.cleaned_data['docfile']
else:
raise forms.ValidationError('Max 2.5 MB allowed. Current size is {0}'.format(current_size))

Django and the POST request: unexpected behaviour with a form

urls.py
from django.conf.urls.defaults import patterns, include, url
import myproject.views
urlpatterns = patterns('', (r'^$', myproject.views.home), (r'^login$', apolla.views.login))
views.py
import django.http
import django.template
import django.shortcuts
def home(request):
return django.http.HttpResponse("Welcome home!")
def login(request):
un = request.POST.get('username')
pa = request.POST.get('password')
di = {'unam': un, 'pass': pa}
if un and pa:
di['act'] = "/"
else:
di['act'] = "/login"
return django.shortcuts.render_to_response('login.html', di,
context_instance=django.template.RequestContext(request))
# Why does this code not send me immediately to "/" with
# username and password filled in?
login.html
<html>
<head>
</head>
<body>
<form name="input" method="post" action="{{ act }}">
{% csrf_token %}
Username:
<input type="text" name="username"><br>
Password:
<input type="password" name="password"><br>
<input id="su" type="submit" value="Submit"><br>
</form>
</body>
</html>
When I run the development server and go to localhost:8000/login and fill in a username and password and push the submit button I am not sent to localhost:8000/ as I expected from my login function in views.py, I just return to localhost:8000/login. But when I fill in any field and submit for the second time I get directed to localhost:8000.
I also used print un and print pa to see if the post caught the data from the username and password fields and it did from the first time, so why am I not being directed to localhost:8000/login from the first submit with both username and password fields filled in?
You can add redirects to your view by:
from django.http import HttpResponseRedirect
def foo_view(request):
# ...
return HttpResponseRedirect('/')