So, I am trying to open an .csv file in Python using Flask. I copies the code from the Python library, but I go from one error message to the other and I don't know what I am doing wrong. The latest error code I get on the below code is: TypeError: invalid file:
Any ideas what I am doing wrong?
My Python code/Flash route is as follows:
#app.route("/admin", methods=["GET", "POST"])
#login_required
def admin():
"""Configure Admin Screen"""
# if user reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# load csv file with portfolio data
with open(request.files["portfolios"]) as csvfile:
portfolios = csv.DictReader(csvfile)
# load csv file in dictionary
for row in portfolios:
print(row['first_name'], row['last_name'])
else:
return render_template("admin.html")
My html/Flask code is:
{% extends "layout.html" %}
{% block title %}
Admin
{% endblock %}
{% block main %}
<h2>Admin Console</h2>
<h3> Upload Portfolio Data</h2>
<form action="{{ url_for('admin') }}" method="post" enctype=multipart/form-data>
<fieldset>
<label class="control-label">Select Portfolio Upload File</label>
<input id="input-1" type="file" class="file" name="portfolios">
<h3>Upload Security Lists</h2>
<label class="control-label">Select Security Upload File</label>
<input id="input-1" type="file" class="file" name="securities">
<div class="form-group">
<button class="btn btn-default" type="submit" value = "upload">Upload</button>
</div>
</fieldset>
</form>
{% endblock %}
The file is already open. open takes a string filename and created an open file object, but you don't need to do that because objects in request.files are already open file-like objects.
portfolios = csv.DictReader(request.files['portfolios'])
Related
I have a simple page with a data entry field and a click button, this will run the API to retrieve the coin data
running the code in a python terminal return with success, but when I try to add it to flask and use the webpage, I get the error 405 method not allowed for the POST.
This is the main python/flask file:
crypto.py
# template libraries
from flask import render_template,url_for,flash,request,redirect,Blueprint
# Coingecko API library
from pycoingecko import CoinGeckoAPI
crypto_simulator = Blueprint('crypto_simulator',__name__)
#crypto_simulator.route('/crypto_simulator', methods=['GET','POST'])
#login_required
def crypto_insert():
if request.form.get("ident") == "formCrypto":
print('Hello')
cg = CoinGeckoAPI()
#crypto_token = request.form.get('crypto_name_html', '')
crypto_token = 'bitcoin'
crypto_currency = 'usd'
response = cg.get_price(ids=crypto_token,
vs_currencies='usd',
include_market_cap='true',
include_24hr_vol='true',
include_24hr_change='true',
include_last_updated_at='true')
crypto_result = response.get(crypto_token,'')
print(crypto_result[crypto_currency])
return render_template('crypto_simulator.html',
formCryptoSimulation=form,
crypto_token=crypto_token,
crypto_currency=crypto_currency,
crypto_result=crypto_result
)
This is the Blueprint routing file:
core.py
# crypto section
#core.route('/crypto_simulator')
def crypto_simulator():
return render_template('crypto_simulator.html')
This is the Flask/Bootstrap front-end:
crypto_simulator.html
{% extends "base.html" %}
{% block content %}
<!-- Simulation Code Start -->
<div class="forms">
<div class="formCrypto">
<form method="post" action="{{ url_for('core.crypto_simulator') }}">
<div class="container">
<div class="row g-3">
<div class="col-sm-3">
<label class="form-label"><b>Crypto Name:</b></label>
<input type="text" class="form-control" name="crypto_name_html" placeholder="Enter Crypto Name" required>
</div>
</div>
</div>
<br>
<div class="d-grid gap-2 d-md-flex justify-content-md-start">
<button id="btn" type="submit" class="btn btn-info">Check Token!</button>
</div>
<input type=hidden name="ident" value="formCrypto">
</form>
<br>
<p>Token: <b>{{crypto_token}}</b>
<p>Price: <b>{{crypto_result}}</b>
</div>
</div>
{% endblock %}
I checked for misspelled lines and anything related but still stuck into how to fix it...
Your form has this:
<form method="post" action="{{ url_for('core.crypto_simulator') }}">
So you are calling the function crypto_simulator in blueprint core:
#core.route('/crypto_simulator')
def crypto_simulator():
return render_template('crypto_simulator.html')
Note that your form does a POST request, so you very logically have to enable the POST method on the function being called like this:
#core.route('/crypto_simulator', methods=['GET','POST'])
I'm building a file storage system using the Google App Engine. Each user is able to login and create directories (Strings) for their accounts using a HTML form. I've been trying to not allow a user to add two directories with the same name but I cannot get it working.
Here is my form in HTML:
<form action="/" method="post">
Add a Directory: <input type="text" name="dir1"/><br/>
<input type="submit" name="button" value="Add Directory"/>
</form>
<br/>
{% for i in directories %}
Directory Name:{{ i.dir1 }}<br/>
<br/>
<form action="/" method="post">
<input type="hidden" name="index" value="{{ loop.index - 1 }}"/>
<input type="submit" value="Delete" name="button"/>
</form>
{% endfor %}
And here is my Python code in which I believe the check should be done:
def post(self):
self.response.headers['Content-Type'] = 'text/html'
action = self.request.get('button')
if action == 'Add Directory':
dir1 = self.request.get('dir1')
user = users.get_current_user()
myuser_key = ndb.Key('MyUser', user.user_id())
myuser = myuser_key.get()
new_directory = Directory(dir1=dir1)
myuser.directories.append(new_directory)
myuser.put()
self.redirect('/')
In your Python function, you could use ndb's get_or_insert method which retrieves an entity if the specified key already exists or creates it if it doesn't.
further to my earlier question, on how to open an csv file in Python, I am still not successful in doing so and going from error to error.
My Python code is as follows:
#app.route("/admin", methods=["GET", "POST"])
#login_required
def admin():
"""Configure Admin Screen"""
# if user reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# load csv file with portfolio data
csvfile = TextIOWrapper(request.files['portfolios'].file, encoding=request.encoding)
portfolios = csv.DictReader(csvfile)
# load csv file in dictionary
for row in portfolios:
print(row['first_name'], row['last_name'])
else:
return render_template("admin.html")
My flask/html code is as follows:
{% extends "layout.html" %}
`{% block title %}
Admin
{% endblock %}
{% block main %}
<h2>Admin Console</h2>
<h3> Upload Portfolio Data</h2>
<form action="{{ url_for('admin') }}" method="post" enctype=multipart/form-
data>
<fieldset>
<label class="control-label">Select Portfolio Upload File</label>
<input id="input-1" type="file" class="file" name="portfolios">
<h3>Upload Security Lists</h2>
<label class="control-label">Select Security Upload File</label>
<input id="input-1" type="file" class="file" name="securities">
<div class="form-group">
<button class="btn btn-default" type="submit" value = "upload">Upload</button>
</div>
</fieldset>
</form>
{% endblock %}
Initially, I literally followed the example from the Python documentation:
import csv
with open('names.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
print(row['first_name'], row['last_name'])
this didnt work as it gave a type error (see my earlier post)
I then removed, as suggested, the "open", which resulted in another error. I then removed the whole with block, which again resulted in an error. Now, the above code is what I am now, and its generating the following error:
builtins.AttributeError
AttributeError: '_io.BytesIO' object has no attribute 'file'
Anyone who can help my csv import nightmare to end?? Txs!!
io.TextIOWrapper takes a io.BytesIO object all right.
You're (almost) passing it, except that you're adding a .file (why??), which is not a field of the io.BytesIO class (request.files['portfolios'] is a io.BytesIO object already)
Just do:
csvfile = TextIOWrapper(request.files['portfolios'], encoding=request.encoding)
I'm new with s3 and trying to upload some files but the I'm getting The system cannot find the file specified: <hashed_file_name>.jpg I understand the issue. When the file is saved at the root, everything is fine. But I don't want to save the file. I want to upload it directly after the action at the form.
def upload_to_s3(file_to_upload, s3_upload_folder):
s3 = boto3.resource('s3',
aws_access_key_id=app.config['ACCESS_KEY_ID'],
aws_secret_access_key=app.config['SECRET_ACCESS_KEY'])
s3.meta.client.upload_file(file_to_upload, app.config['BUCKET_NAME'], s3_upload_folder)
def _user_img_folder(form, file_name):
username = session['name']
vacation_name = slugify(form.test_name.data)
directory = os.path.join(username, test_name)
directory = os.path.join(UPLOAD_FOLDER, directory)
return directory + '/' + file_name
#app.route('/post', methods=['GET', 'POST'])
def test():
if _is_image():
uploaded_images = request.files.getlist('photo')
for image in uploaded_images:
processed_image_name = _hash_image_name(image) # Returns hashed filename with extension
directory = _user_img_folder(form, processed_image_name)
upload_to_s3(str(processed_image_name), str(directory))
return render_template('test.html', form=form, error=error)
Thank you for your help.
EDIT 1:
{# Heavily edited #}
{% extends '_base.html' %}
{% block content %}
<form class="logVacation" enctype=multipart/form-data role="form" method="post" action="/post">
{{ form.csrf_token }}
{{ form.vacation_name(placeholder="Name Your Vacation")}}
<br>
{{ form.location(placeholder="Where was it?") }}
<br>
{{ form.with_who(placeholder='Who was with you') }}
<br><br>
{{ form.description(placeholder="Tell us about your vacation... or not.") }}<br>
{{ form.when(class="datepicker", placeholder="when?") }}
<br><br>
{{ form.photo(multiple="multiple") }}
<br>
<button class="btn btn-sm btn-success" value="upload" type="submit">Done</button>
</form>
{% endblock %}
Found the answer:
I've changed the
s3.meta.client.upload_file(file_to_upload, app.config['BUCKET_NAME'], s3_upload_folder)
to:
s3.Object(app.config['BUCKET_NAME'], s3_upload_folder).put(Body=image)
so the trick is, you must either have the file on disk and provide filepath with file_to_upload OR provide the file itself as I demonstrated in this answer.
Hoping someone can help cure my stupidity. I am creating a webapp where I need to upload csv files and process them. I am struggling to get my code to work in its simplest form. I can get the page to load up but as soon as I press the submit button to post the file I get a 403 Forbidden Error: Access was denied to this resource.
When I run it in the google app interactive console it does not give me any errors. Can some one point me in the right direction please.
HTML:
{% extends base_layout %}
{% block header_title %}
{% trans %}Upload Documents{% endtrans %}
{% endblock %}
{% block content %}
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="myfile">
<br>
<input type="submit" name="submit" value="Submit">
{% endblock %}
Handler class:
class Upload(BaseHandler):
def get(self):
return self.render_template('upload.html')
def post(self):
file = self.request.POST.getall('myfile')
#file will be process with data going into models here.
self.response.out.write("success")
You cannot simply upload a file to app engine since the file system is read only. You have to upload to either cloud storage or blob storage. When using either you have to use the facilities for each.
The easiest and fastest way to upload files via a form is with the blobstore api.