I generated a csv file through my code, and after generation, it goes to the path of my project, my project called sample, so the file path sample/output.csv.. I added a function for the download and I called this function inside the my main function ( home), but the download is not working, what I'm doing wrong?
def save_file(request):
# data = open(os.path.join(settings.PROJECT_PATH,'data/table.csv'),'r').read()
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=output1.csv'
return response
def home(request):
if request.method=="POST":
img = UploadForm(request.POST, request.FILES)
if img.is_valid():
logging.warning('Watch out!') # will print a message to the console
# paramFile = request.FILES['pic']
paramFile =io.TextIOWrapper(request.FILES['pic'].file)
portfolio1 = csv.DictReader(paramFile)
print(type(paramFile))
users = []
# users = [row["BASE_NAME"] for row in csv_file]
# users = zip(*csv_file)
# users = [row[0] for row in csv_file]
# for row in portfolio1:
# users.append(row)
users = [row["BASE_NAME"] for row in portfolio1]
print(len(users))
my_list = users
vectorizer = CountVectorizer()
dtm = vectorizer.fit_transform(my_list)
lsa = TruncatedSVD(n_components=100)
dtm_lsa = lsa.fit_transform(dtm)
dtm_lsa = Normalizer(copy=False).fit_transform(dtm_lsa)
similarity = np.asarray(numpy.asmatrix(dtm_lsa) * numpy.asmatrix(dtm_lsa).T)
# print(1-similarity)
k = len(my_list)
dist1 = np.subtract(np.ones((k, k), dtype=np.float), similarity)
# dist1=similarity
# dist1.astype(float)
#print(dist1)
# print(cosine_similarity(tfidf_matrix[3:4], tfidf_matrix))
# float dist = 1 - similarity;
data2 = np.asarray(dist1)
arr_3d = data2.reshape((1, k, k))
# arr_3d= 1- arr_3d
#print(arr_3d)
no_clus = 40
for i in range(len(arr_3d)):
# print (i+1910)
# km = AgglomerativeClustering(n_clusters=no_clus, linkage='ward').fit(arr_3d[i])
km = AgglomerativeClustering(n_clusters=no_clus, linkage='average').fit(arr_3d[i])
# km = AgglomerativeClustering(n_clusters=no_clus, linkage='complete').fit(arr_3d[i])
# km = MeanShift()
# km = KMeans(n_clusters=no_clus, init='k-means++')
# km = MeanShift()
# km = km.fit(arr_3d[i])
# print km
labels = km.labels_
csvfile = r'C:\users\A6B0SZZ\PycharmProjects\sample\media\images\export.csv'
csv_input = pd.read_csv(csvfile, encoding='latin-1')
csv_input['cluster_ID'] = labels
csv_input['BASE_NAME'] = my_list
csv_input.to_csv('output.csv', index=False)
clus_groups = list()
for j in range(no_clus):
# print(" cluster no %i:%s" % (j, [my_list[i] for i, x in enumerate(labels) if x == j]))
list_of_ints = ([my_list[i] for i, x in enumerate(labels) if x == j])
clus_groups.append(' '.join(list_of_ints))
vectorizer = CountVectorizer()
dtm = vectorizer.fit_transform(my_list)
lsa = TruncatedSVD(n_components=100)
dtm_lsa = lsa.fit_transform(dtm)
dtm_lsa = Normalizer(copy=False).fit_transform(dtm_lsa)
similarity = np.asarray(numpy.asmatrix(dtm_lsa) * numpy.asmatrix(dtm_lsa).T)
k = len(my_list)
dist1 = 1 - similarity
data2 = np.asarray(dist1)
arr_3d = data2.reshape((1, k, k))
# arr_3d= 1- arr_3d
no_clus = 5
for i in range(len(arr_3d)):
# print (i+1910)
# km = AgglomerativeClustering(n_clusters=no_clus, linkage='ward').fit(arr_3d[i])
# km = AgglomerativeClustering(n_clusters=no_clus, linkage='average').fit(arr_3d[i])
# km = AgglomerativeClustering(n_clusters=no_clus, linkage='complete').fit(arr_3d[i])
km = KMeans(n_clusters=5, init='k-means++')
km = km.fit(arr_3d[i])
# print km
labels2 = km.labels_
# error = km.inertia_
print(labels2)
labels = labels.tolist()
labels2 = labels2.tolist()
# new=list()
csv_input = pd.read_csv(r'C:\users\A6B0SZZ\PycharmProjects\sample\output.csv',encoding='latin-1')
labels1 = csv_input['cluster_ID']
new_list = []
for k in labels1:
new_list.append(labels2[k]) # lookup the value in list2 at the index given by list1
print(new_list)
print(len(new_list))
csv_input = pd.read_csv(r'C:\users\A6B0SZZ\PycharmProjects\sample\output.csv',encoding='latin-1')
csv_input['cluster_ID'] = labels
csv_input['BASE_NAME'] = my_list
csv_input['User_Map'] = new_list
csv_input.to_csv('output1.csv', index=False)
# my_list = portfolio
save_file(request)
# return HttpResponseRedirect(reverse('portfolio'))
return render(request, 'home.html', {'labels': labels})
else:
img=UploadForm()
images=Upload.objects.all()
return render(request,'home.html',{'form':img,'images':images})
And my home.html is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="padding:40px;margin:40px;border:1px solid #ccc">
<h1>Upload the CSV File to Run the Algorithm on:</h1>
<form action="#" method="post" enctype="multipart/form-data">
{% csrf_token %} {{form}}
<input type="submit" value="Upload" />
</form>
{% for img in images %}
{{forloop.counter}}.{{ img.pic.name }}
({{img.upload_date}})<hr />
{% endfor %}
</div>
</body>
</html>
Url.py:
from django.conf.urls import url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^upload/$', 'uploader.views.home', name='labels'),
url(r'^admin/', admin.site.urls),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Edit, my function now is: but still not working:
def save_file(request):
# data = open(os.path.join(settings.PROJECT_PATH,'data/table.csv'),'r').read()
# file_path = r'C:\users\A6B0SZZ\PycharmProjects\sample\output1.csv'
# fsock = open(file_path, "r")
fsock= pd.read_csv(r'C:\users\A6B0SZZ\PycharmProjects\sample\output1.csv', encoding='latin-1')
response = HttpResponse(fsock, content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=output1.csv'
return response
For the main issue with your download not working, please take a look at this answer because the first argument for your HttpResponse should be your data to actually send.
Now, also you should do is look at interacting with the storage classes & MEDIA_ROOT.
This will enable your project to work locally or remotely on a server. Looking at what you've posted I'll assume your settings.py contains something like MEDIA_ROOT = 'C:\users\A6B0SZZ\PycharmProjects\sample\media'
You might want to consider some more generic, reusable paths in your settings.py (depending on how your project is structured, but this is what I have);
SETTINGS_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_DIR = os.path.abspath(os.path.join(SETTINGS_DIR, '../'))
BASE_DIR = os.path.abspath(os.path.join(PROJECT_DIR, '../'))
STATIC_ROOT = os.path.join(BASE_DIR, 'static-collection')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Some good reading here would be Managing Files which takes you over the various ways to create files & access their paths.
If you want to send the file to the browser that way, the file has to be un a directory directly accessible by webserver. In most cases, the folder where all Python code is stored is not accesible.
Try to put the file in a directory accesible by webserver. Another way of sending the file is reading it through Python and sending it inline, like the user is doing in this question: django return file over HttpResponse - file is not served correctly
I ended it up using FILEwrapper:
def send_file(request):
filename = settings.MEDIA_ROOT +'/'+ 'output1.csv'
#filename= r"C:\Users\A6B0SZZ\PycharmProjects\sample\media\output1.csv"
download_name ="output1.csv"
wrapper = FileWrapper(open(filename))
response = HttpResponse(wrapper,content_type='text/csv')
response['Content-Disposition'] = "attachment; filename=%s"%download_name
return response
Related
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Store large data or a service connection per Flask session
(1 answer)
Closed 2 years ago.
I am taking input(city name) from the user using a form and using the input(city name) I am fetching a real time weather data after some pre processing a 'sample' numpy variable is created and I am trying to use 'sample' in a different funtion to display the output on a different page.
Here is the app.py code:
from flask import Flask, request, jsonify, render_template
import requests
import math
import numpy as np
import pickle
app = Flask(__name__)
modelMLR = pickle.load(open('modelMLR.pkl','rb'))
#app.route('/')
def home():
return render_template('main.html')
#app.route('/algos', methods = ['GET','POST'])
def algos():
city = request.form['location']
api_address = "https://api.openweathermap.org/data/2.5/weather?appid=33a306ae5533eae0fe34e94953cde0a7&q="
url = api_address+city
json_data = requests.get(url).json()
#for Multiple linear Regression
L1=[]
#temperature
kelvin_temp = json_data["main"]["temp_min"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data1 = math.floor(fahrenheit_temp)
L1.append(formatted_data1)
kelvin_temp = json_data["main"]["temp_max"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data2 = math.floor(fahrenheit_temp)
L1.append(formatted_data2)
#Humidity
L1.append(80)
formatted_data4 = json_data["main"]["humidity"]
L1.append(formatted_data4)
#sea level pressure
L1.append(990)
L1.append(1010)
formatted_data5 = json_data["main"]["pressure"]
L1.append(formatted_data5)
#cloud cover
formatted_data6 = json_data["clouds"]["all"]
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
#shortwave radiation
L1.append(0)
#wind speed
L1.append(0)
formatted_data7 = json_data["wind"]["speed"]
L1.append(formatted_data7)
#wind gust
L1.append(0)
L1.append(0)
sample = np.array(L1)
sample= sample.reshape(1, -1)
return render_template("algos.html")
#app.route('/MLR')
def predict_MLR():
prediction = modelMLR.predict(sample)
return render_template('MLR.html', prediction_text = "The current precipitation is: {}".format(prediction))
if __name__ == "__main__":
app.run(debug = False)
I want to use variable 'sample' of algos() function in predict_MLR() function so that I can predict the output and display it on MLR.html page.
main.html:
<!doctype html>
<body>
<h1> Rainfall prediction.. </h1><br>
<form method = "POST" action="{{url_for('algos')}}">
<button type="button"><img width="13px" height="13px" src="back.jpg"></button>
<input type = "text" placeholder="Search for your city.." style="width:300px" name = "location">
<button type = "submit" value="submit"><img src = "search.png" height="13px" width="13px"></button>
</form>
</body>
</html>
algos.html:
<!doctype html>
<html>
<body>
<h1> Rainfall prediction.. </h1><br>
<h1>Multiple Linear Regression<h1>
</body>
</html>
MLR.html:
<!doctype html>
<html>
<h1> Rainfall prediction.. </h1><br>
<h2>{{prediction_text}}</h2>
</html>
A simpler way to write this would be to first define the agios function which returns sample:
def algos(city):
api_address = "https://api.openweathermap.org/data/2.5/weather?appid=33a306ae5533eae0fe34e94953cde0a7&q="
url = api_address+city
json_data = requests.get(url).json()
#for Multiple linear Regression
L1=[]
#temperature
kelvin_temp = json_data["main"]["temp_min"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data1 = math.floor(fahrenheit_temp)
L1.append(formatted_data1)
kelvin_temp = json_data["main"]["temp_max"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data2 = math.floor(fahrenheit_temp)
L1.append(formatted_data2)
#Humidity
L1.append(80)
formatted_data4 = json_data["main"]["humidity"]
L1.append(formatted_data4)
#sea level pressure
L1.append(990)
L1.append(1010)
formatted_data5 = json_data["main"]["pressure"]
L1.append(formatted_data5)
#cloud cover
formatted_data6 = json_data["clouds"]["all"]
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
#shortwave radiation
L1.append(0)
#wind speed
L1.append(0)
formatted_data7 = json_data["wind"]["speed"]
L1.append(formatted_data7)
#wind gust
L1.append(0)
L1.append(0)
sample = np.array(L1)
sample= sample.reshape(1, -1)
return sample
Then have a single route which returns a different result based on the request.method:
#app.route('/')
def home():
if request.method == 'POST':
city = request.form['location']
sample = algos(city)
prediction = modelMLR.predict(sample)
return render_template('main.html', prediction_text = "The current precipitation is: {}".format(prediction))
else:
# GET request, just render the home page
return render_tempate('main.html')
if __name__ == "__main__":
app.run(debug = False)
Notice that prediction_text is only passed through in the event of a POST request.
Now just define a template which handles this case with an if clause:
<!doctype html>
<body>
<h1> Rainfall prediction.. </h1><br>
<form method = "POST" action="{{url_for('home')}}">
<button type="button"><img width="13px" height="13px" src="back.jpg"></button>
<input type = "text" placeholder="Search for your city.." style="width:300px" name = "location">
<input type = "submit" value="submit" />
</form>
{% if prediction_text %}
<h1> Rainfall prediction.. </h1><br>
<h2>{{prediction_text}}</h2>
{% endif %}
</body>
</html>
In the event that you hit the / endpoint with a GET request, the prediction is not shown.
I am developing program where I can upload excel invoice .xlsx file using Flask and then store that file to mysql when user click submit button. There are total three files involved. getFile.py which is Flask to upload file using index.html. exlTomySQL.py store data to mysql from file received by index.html. I am new to Flask and don't know how to process data after clicking submit button on index.html to process .xlsx file and return response for user.
getFile.py
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
fileDetails = request.form
myFile = fileDetails['myfile']
return myFile
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Page</title>
</head>
<body>
<form method="POST" action="">
<label for="myfile">Select a file:</label>
<br>
<input type="file" id="myfile" name="myfile">
<br>
<input type="submit">
</form>
</body>
</html>
exlToSQL.py
import openpyxl
import math
import datetime
import mysql.connector
wb = openpyxl.load_workbook('myFile')
sheet = wb.active
# count rows of data for column 2 as it represent description
def countRows():
count = 0
for i in range(1, 100, 1):
if sheet.cell(row=i, column=2).value != None:
count = i
return count
# list each row description, (not counting quantity), gst amount and last column(total excluding GST)
def readRows():
description = []
# quantity = []
amount = []
gstAmount = []
for i in range(3, countRows() + 1, 1):
description.append(sheet.cell(row=i, column=2).value)
# quantity.append(sheet.cell(row=i, column=5).value)
gstAmount.append(sheet.cell(row=i, column=10).value)
amount.append(sheet.cell(row=i, column=11).value)
uperCaseDescription = [desc.upper()
for desc in description]
return uperCaseDescription, gstAmount, amount
# count all list totals for GST and Amount
def countTotals():
uperCaseDescription, gstAmount, amount = readRows()
totalGST = round(sum(gstAmount), 2)
subTotalAmount = round(sum(amount), 2)
totalAmountOfInvoice = round((totalGST + subTotalAmount), 2)
return totalGST, subTotalAmount, totalAmountOfInvoice
# get static data of invoice e.g. invoice number,
# invoice date, sub total, total gst, total inc gst
print(countRows())
print(countTotals())
invoice_number = sheet.cell(row=1, column=1).value
print("Invoice Number:", invoice_number)
invoice_date = sheet.cell(row=1, column=2).value
print("Invoice Date:", invoice_date)
sun_offset = (invoice_date.weekday() - 6) % 7
weekEnd = invoice_date - datetime.timedelta(days=sun_offset)
print("Week End Date:", weekEnd)
print(readRows())
# merge all list into tuple
def mergeList():
uperCaseDescription, gstAmount, amount = readRows()
mergeTuple = tuple(zip(uperCaseDescription, gstAmount, amount))
return mergeTuple
# MySql connection and transfer data to mysql
mydb = mysql.connector.connect(
host="localhost",
user="root",
password="Vrishab2145",
database="testdbOne"
)
# creating database_cursor to perform SQL operation
mycursor = mydb.cursor()
sqlFormula = "INSERT INTO invoice (description, gstAmount, totalExGst) VALUES (%s,%s,%s)"
mycursor.executemany(sqlFormula, mergeList())
mydb.commit()
You can save the file being uploaded by making some changes in your code as shown below.
Once you have saved the file, you can deal with the file processing to store the data to MySQL. You can also delete the file previously saved once the processing is done.
getFile.py
from flask import Flask, render_template, request
import os
app = Flask(__name__)
app.config["UPLOADS"] = "C:/FlaskSandbox/uploads" # path where uploads are saved. Can also be UNIX path
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
userfile = request.files['myfile']
userfile.save(os.path.join(app.config["UPLOADS"], userfile.filename))
print('File Saved!')
# call your file processing functions below
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Page</title>
</head>
<body>
<form method="POST" action="" enctype=multipart/form-data>
<label for="myfile">Select a file:</label>
<br>
<input type="file" id="myfile" name="myfile">
<br>
<input type="submit">
</form>
</body>
</html>
Bellow Code working perfectly fine. After spending so many days finally worked out.
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
import os
import openpyxl
import math
import datetime
import mysql.connector
app = Flask(__name__)
# path where uploads are saved. Can also be UNIX path
app.config["UPLOADS"] = "/Users/vrishabpatel/Desktop/PythonPrep/FlaskApp/uploads"
#app.route('/', methods=['GET', 'POST'])
def index():
mydb = mysql.connector.connect(
host="localhost",
user="root",
password="Vrishab2145",
database="testdbOne"
)
if request.method == 'POST':
userfile = request.files['myfile']
userfile.save(os.path.join(app.config["UPLOADS"], userfile.filename))
print('File Saved!')
# call your file processing functions below
wb = openpyxl.load_workbook(userfile)
sheet = wb.active
mycursor = mydb.cursor()
sqlFormula = "INSERT INTO invoice (description, gstAmount, totalExGst) VALUES (%s,%s,%s)"
mycursor.executemany(sqlFormula, mergeList(sheet))
mycursor.close()
mydb.commit()
return render_template('index.html')
# creating database_cursor to perform SQL operation
# countRows()
# readRows()
# countTotals()
def countRows(sheet):
count = 0
for i in range(1, 100, 1):
if sheet.cell(row=i, column=2).value != None:
count = i
return count
def readRows(sheet):
description = []
# quantity = []
amount = []
gstAmount = []
for i in range(3, countRows(sheet) + 1, 1):
description.append(sheet.cell(row=i, column=2).value)
# quantity.append(sheet.cell(row=i, column=5).value)
gstAmount.append(sheet.cell(row=i, column=10).value)
amount.append(sheet.cell(row=i, column=11).value)
uperCaseDescription = [desc.upper()
for desc in description]
return uperCaseDescription, gstAmount, amount
def countTotals(sheet):
uperCaseDescription, gstAmount, amount = readRows(sheet)
totalGST = round(sum(gstAmount), 2)
subTotalAmount = round(sum(amount), 2)
totalAmountOfInvoice = round((totalGST + subTotalAmount), 2)
return totalGST, subTotalAmount, totalAmountOfInvoice
def mergeList(sheet):
uperCaseDescription, gstAmount, amount = readRows(sheet)
mergeTuple = tuple(zip(uperCaseDescription, gstAmount, amount))
return mergeTuple
if __name__ == "__main__":
app.run(debug=True)
Please Before Dislike this Question ask me what you don't understand Hello Guys i have data generation program which will do lots of computation so i cannot paste my whole program here so only talking about my program All the computation of the program starts with reading the file so when i'm selecting multiple CSV file in web page in "choose file" option i need to validate the columns numbers(should be same) of the all csv file and columns headers name should also match.. program i have written is like this:
from flask import Flask, render_template
import os
import csv
import pandas as pd
import numpy as np
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#app.route("/")
def index():
print("Loading the root file")
return render_template("upload.html")
#app.route("/upload", methods=['POST'])
def upload():
target = os.path.join(APP_ROOT, 'input/')
print("target-",target)
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist("source_fileName"):
print("file-",file)
filename = file.filename
print("filename-",filename)
destination = "/".join([target, filename])
print("destination-",destination)
file.save(destination)
print("file>",file)
global tempFile
tempFile = destination
print("tempFile - " + tempFile)
return redirect("/compute", )
def compute():
readerForRowCheck = pd.read_csv(tempFile)
for row in readerForRowCheck:
if (len(row) != 8):
return render_template("Incomplete.html")
headerColumn1 = row[0];
headerColumn2 = row[1];
headerColumn3 = row[2];
headerColumn4 = row[3];
headerColumn5 = row[4];
headerColumn6 = row[5];
headerColumn7 = row[6];
headerColumn8 = row[7];
if (headerColumn1 != "Asset_Id") or (headerColumn2 != "Asset Family") \
or (headerColumn3 != "Asset Name") or (headerColumn4 != "Location")or (headerColumn5 != "Asset Component") \
or (headerColumn6 != "Keywords") or (headerColumn7 != "Conditions") or (headerColumn8 != "Parts") :
return render_template("incomplete.html")
.....................................so on to then it will go to perform other task
HTML program:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> upload </title>
</head>
<body>
<div class="container">
<h1>Large Data Generation</h1>
<form id = "upload-form" action="{{ url_for('upload') }}" method="POST" enctype="multipart/form-data">
<div id="file-selector">
<p>
<strong>Source File: </strong>
<input id="source_fileName" type="file" name="source_fileName" accept="csv/*" multiple />
</p>
</div>
<input type="submit" value="Generate Data" id="upload-button" >
</form>
</div>
</body>
Note:**I have only given lines of code which important otherwise its contain lots of code **Here i'm getting that how should i validate the csv file on the columns numbers and name should be same i know my validation for reading csv file is not correct that why i'm here please Help me.....thanks
I You are having multiple files then you need to create instance of dataframe for each file
Upload function will look like this:
def upload():
target = os.path.join(APP_ROOT, 'input/')
print("target-",target)
if not os.path.isdir(target):
os.mkdir(target)
abs_path_files=[]
for file in request.files.getlist("source_fileName"):
print("file-",file)
filename = file.filename
print("filename-",filename)
destination = "/".join([target, filename])
print("destination-",destination)
file.save(destination)
print("file>",file)
tempFile = os.path.abspath(destination)
abs_path_files.append(tempfile)
print("tempFile - " + tempFile)
return redirect(url_for("compute", files_list=abs_path_files))
Compute Function will look like this:
def compute(files_list):
dataFrames=[]
for f in files_list:
dataFrame=pd.read_csv(f)
dataFrames.append(dataFrame)
col_in_files = set([",".join(list(f.column.values)) for f in dataFrames])
if len(col_in_files)==1:
#then process your data here
I have a django backed website on Heroku and every time I try to view/download the upload excel files after uploading them on the Heroku website I get this error:
Not Found: The requested URL /excel_files/<file> was not found on this server.
Here is my views.py:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .forms import UploadForm
from django.conf import settings
import os
import openpyxl, re
def index(request):
"""The home page which generates the donor list html page"""
if request.method != 'POST':
form = UploadForm()
else:
form = UploadForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
file = request.FILES['fileobj'].name
file_corrected = file.replace(" ", "_")
path = os.path.join(settings.MEDIA_ROOT, file_corrected)
wb = openpyxl.load_workbook(path)
sheet = wb.get_sheet_by_name('Sheet1')
text_file = open('upload/templates/upload/donor_list.html', 'w')
html1 = "{% extends 'upload/base.html' %}" + "\n" + "{% block header %}" + "\n" + " <h1>Donor List</h1>" + "\n" + "{% endblock header %}" + "\n" + "{% block content %}" + "\n"
html2 = "{% endblock content %}"
text_file.write(html1)
for rowNum in range(1, sheet.max_row + 1):
firstName = str(sheet.cell(row=rowNum, column=1).value)
if firstName == "None":
firstName = "\n"
lastName = str(sheet.cell(row=rowNum, column=2).value)
addNum = re.compile(r'\d(\d)*')
addressNumber1 = addNum.search(str(sheet.cell(row=rowNum, column=3).value))
if addressNumber1 is None:
addressNumber = ""
if addressNumber1 is not None:
addressNumber = addressNumber1.group(0)
donate = str(sheet.cell(row=rowNum, column=4).value)
donate = "$" + donate
if donate == "$None":
donate = ""
date = str(sheet.cell(row=rowNum, column=7).value)
year = date[2:4]
if year == "ne":
year = ""
if firstName == "\n" and lastName != "None":
firstName = str(sheet.cell(row=rowNum, column=2).value)
lastName = str(sheet.cell(row=rowNum, column=3).value)
addressNumber1 = addNum.search(str(sheet.cell(row=rowNum, column=4).value))
addressNumber = addressNumber1.group(0)
donate = str(sheet.cell(row=rowNum, column=5).value)
donate = "$" + donate
date = str(sheet.cell(row=rowNum, column=8).value)
year = date[2:4]
if firstName is "_" or lastName is "Anonymous":
text_file.write(""" <p>{} (Mr./Ms.) {} {} {}.</p>""".format(addressNumber, lastName, donate, year) + '\n')
else:
text_file.write(""" <p>{} {} {} {}.</p>""".format(addressNumber, firstName, donate, year) + '\n')
text_file.write(html2)
text_file.close()
return donor_list(request)
context = {'form': form}
return render(request, 'upload/index.html', context)
def instructions(request):
"""The how-to for file uploading"""
return render(request, 'upload/instructions.html')
def donor_list(request):
"""Webpage with the donor list after upload"""
return render(request, 'upload/donor_list.html')
and here is my settings.py as it relates to the Heroku website:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
# Heroku settings
cwd = os.getcwd()
if cwd == '/app' or cwd[:4] == '/tmp':
import dj_database_url
DATABASES = {
'default': dj_database_url.config(default='postgres://localhost')
}
# Honor the "X-Forwarded_Proto' header for request.is.secure().
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Allow only Heroku to host the project
ALLOWED_HOSTS = ['WEBSITE_URL_HERE']
DEBUG = False
# Static asset configuration
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
MEDIA_ROOT = os.path.join(BASE_DIR, 'excel_files')
MEDIA_URL = '/excel_files/'
Notice that my views.py after upload displays the excel file as text using openpyxl module, but i find it odd that I can't seem to access these excel files on my Heroku admin page; they are listed but I can't download them as I described above. Beginner friendly answers are greatly appreciated.
You must not upload files to the filesystem on Heroku. As the documentation explains, the filesystem is ephemeral and is not shared between dynos. Anything uploaded will only be seen by the dyno that created it, and will be completely lost when that dunno restarts.
You must use a permanent store, for example S3.
I am trying to get the fileadmin to get multiple files uploaded but can't figure out how to do that.
Currently in the below reference I can only upload one file at a time.
https://github.com/flask-admin/flask-admin/blob/master/examples/file/app.py
(New Link to to file: https://github.com/mrjoes/flask-admin/blob/master/examples/file/app.py )
I tried updating the html template to have multiple="" but that didn't helped to upload multiple files.
Further looking into this I think this html file needs to have multiple=""
Python27\Lib\site-packages\flask_admin\templates\bootstrap3\adminC:\Python27\Lib\site-packages\flask_admin\templates\bootstrap3\admin\lib.html
Although I am not sure where/how to add this tag without actually overwriting the source file.
You should custom ImageUploadInput and ImageUploadField as follows.
import ast
from PIL import Image
from wtforms.widgets import html_params, HTMLString
from wtforms.utils import unset_value
from flask_admin.helpers import get_url
from flask_admin.form.upload import ImageUploadField
from flask_admin._compat import string_types, urljoin
class MultipleImageUploadInput(object):
empty_template = "<input %(file)s multiple>"
# display multiple images in edit view of flask-admin
data_template = ("<div class='image-thumbnail'>"
" %(images)s"
"</div>"
"<input %(file)s multiple>")
def __call__(self, field, **kwargs):
kwargs.setdefault("id", field.id)
kwargs.setdefault("name", field.name)
args = {
"file": html_params(type="file", **kwargs),
}
if field.data and isinstance(field.data, string_types):
attributes = self.get_attributes(field)
args["images"] = " ".join(["<img src='{}' /><input type='checkbox' name='{}-delete'>Delete</input>"
.format(src, filename) for src, filename in attributes])
template = self.data_template
else:
template = self.empty_template
return HTMLString(template % args)
def get_attributes(self, field):
for item in ast.literal_eval(field.data):
filename = item
if field.thumbnail_size:
filename = field.thumbnail_size(filename)
if field.url_relative_path:
filename = urljoin(field.url_relative_path, filename)
yield get_url(field.endpoint, filename=filename), item
class MultipleImageUploadField(ImageUploadField):
widget = MultipleImageUploadInput()
def process(self, formdata, data=unset_value):
self.formdata = formdata # get the formdata to delete images
return super(MultipleImageUploadField, self).process(formdata, data)
def process_formdata(self, valuelist):
self.data = list()
for value in valuelist:
if self._is_uploaded_file(value):
self.data.append(value)
def populate_obj(self, obj, name):
field = getattr(obj, name, None)
if field:
filenames = ast.literal_eval(field)
for filename in filenames[:]:
if filename + "-delete" in self.formdata:
self._delete_file(filename)
filenames.remove(filename)
else:
filenames = list()
for data in self.data:
if self._is_uploaded_file(data):
self.image = Image.open(data)
filename = self.generate_name(obj, data)
filename = self._save_file(data, filename)
data.filename = filename
filenames.append(filename)
setattr(obj, name, str(filenames))
After that, You can use them as image upload example in flask-admin
class ModelHasMultipleImages(db.Model):
id = db.Column(db.Integer(), primary_key=1)
# len of str representation of filename lists may exceed the len of field
image = db.Column(db.String(128))
class ModelViewHasMultipleImages(ModelView):
def _list_thumbnail(view, context, model, name):
if not model.image:
return ''
def gen_img(filename):
return '<img src="{}">'.format(url_for('static',
filename="images/custom/" + form.thumbgen_filename(image)))
return Markup("<br />".join([gen_img(image) for image in ast.literal_eval(model.image)]))
column_formatters = {'image': _list_thumbnail}
form_extra_fields = {'image': MultipleImageUploadField("Images",
base_path="app/static/images/custom",
url_relative_path="images/custom/",
thumbnail_size=(400, 300, 1))}
The image filed of ModelHasMultipleImages store the str represent of filename list.
Dropzone is the best way to do this
Download with
pip install flask flask-uploads flask-dropzone
The Python app.py should look somthhing like this
# app.py
from flask import Flask, render_template
from flask_dropzone import Dropzone
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
import os
app = Flask(__name__)
dropzone = Dropzone(app)
# Dropzone settings
app.config['DROPZONE_UPLOAD_MULTIPLE'] = True
app.config['DROPZONE_ALLOWED_FILE_CUSTOM'] = True
app.config['DROPZONE_ALLOWED_FILE_TYPE'] = 'image/*'
app.config['DROPZONE_REDIRECT_VIEW'] = 'results'
# Uploads settings
app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd() + '/uploads'
photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app) # set maximum file size, default is 16MB
#app.route('/')
def index():
return render_template('index.html')
#app.route('/results')
def results():
return render_template('results.html')
And result.html looks as follows
# templates/results.html
<h1>Hello Results Page!</h1>
Back<p>
<ul>
{% for file_url in file_urls %}
<li><img style="height: 150px" src="{{ file_url }}"></li>
{% endfor %}
</ul>
index.html looks something like this
# templates/index.html
<!DOCTYPE html>
<html>
<head>
<title>Flask App</title>
{{ dropzone.load() }}
{{ dropzone.style('border: 2px dashed #0087F7; margin: 10%; min-height: 400px;') }}
</head>
<body>
<h1>Hello from Flask!</h1>
{{ dropzone.create(action_view='index') }}
</body>
</html>