Displaying CSV file as HTML page using Flask - python

I have a CSV file called random.csv which I want to render on a html page if the user is logged in. I've tried using tablib for this.
__init__.py
from flask import Flask
import tablib
app = Flask(__name__)
dataset = tablib.Dataset()
with open(os.path.join(os.path.dirname(__file__), 'random.csv')) as f:
dataset.csv = f.read()
routes.py
#app.route('/dataset', methods=['GET', 'POST'])
#login_required
def dataset():
return dataset.html
This is the index.html file from where I want to link to the html page for the csv file.
{% extends "base.html" %}
{% block content %}
<p>Click to see CSV </p>
{% endblock %}
And this is the dataset.html file where I want to see the CSV data.
{% extends "base.html" %}
{% block content %}
{% endblock %}
I'm getting this error:
AttributeError: 'function' object has no attribute 'html'
The error is on the line in routes.py file where I return the dataset.html file.

I solved it by using pandas instead tablib. In my routes.py file just did this:
import pandas as pd
#app.route('/dataset', methods=['GET', 'POST'])
#login_required
def dataset():
table = pd.read_csv('filepath', encoding= 'unicode_escape')
return render_template("dataset.html", data=table.to_html())

The reason is that you shadowed whatever the variable was with the function name:
def dataset():
return dataset.html
dataset is the function. If it was something else before, naming your function dataset replaced whatever that variable was.

Related

Uploading and reading a CSV file with Flask

I'm currently in the process of making a program to upload and read csv files. I'm throwing a key error when submitting a file to be uploaded and can't really seem to figure out why and was hoping for some help. It uploaded and saved the file before I tried adding the read file functionality but after that, it started having issues. The error is saying that 'filename' is a key error even though it seemed to work fine before I tried reading the file. Help or leading me down the right path would be greatly appreciated. Thanks so much!
Views.py
from flask import render_template, request, redirect
from app import app
import os
import csv
#app.route('/', methods=["GET", "POST"])
def index():
data = []
if request.method == 'POST':
if request.files:
uploaded_file = request.files['filename'] # This line uses the same variable and worked fine
uploaded_file.save(os.path.join(app.config['FILE_UPLOADS'], uploaded_file.filename))
f = request.form['filename'] # This is the line throwing the error
with open(f) as file:
csv_file = csv.reader(file)
for row in csv_file:
data.append(row)
return redirect(request.url)
return render_template('index.html', data=data)
#app.route('/help')
def help():
return render_template('help.html')
app.config['FILE_UPLOADS'] = "C:\\Users\\Zachary\\Documents\\VSCode_Projects\\monday_webapp\\app\\static\\file\\uploads"
Index.html
{% extends "base.html" %}
{% block title %}Home{% endblock %}
{% block body %}
<div class="jumbotron">
<h1 style='text-align: center'>Zach's Web Application</h1>
</div>
<div>
<p class="lead">Upload a csv file to view its data.</p>
<form method="POST" enctype="multipart/form-data" action="/">
<input type="file" id="myFile" name="filename" accept=".csv">
<input type="submit">
</form>
</div>
<div>
{{ data }}
</div>
<div>
{% endblock %}
In flask request.form["input_name"] is used to get the input data, but not for input type=files which are accesible through request.files["input_name"], always using enctype=multipart/form-data in the form. You can get more info in the oficial documentation:
https://flask.palletsprojects.com/en/1.1.x/patterns/fileuploads/
On the other hand, request.files['filename'] is a FileStorage type, the function open(f) expects str, bytes or os.PathLike object, not FileStorage.
The following code should works:
from flask import render_template, request, redirect
from app import app
import os
import csv
#app.route('/', methods=["GET", "POST"])
def index():
data = []
if request.method == 'POST':
if request.files:
uploaded_file = request.files['filename'] # This line uses the same variable and worked fine
filepath = os.path.join(app.config['FILE_UPLOADS'], uploaded_file.filename)
uploaded_file.save(filepath)
with open(filepath) as file:
csv_file = csv.reader(file)
for row in csv_file:
data.append(row)
return redirect(request.url)
return render_template('index.html', data=data)
#app.route('/help')
def help():
return render_template('help.html')
app.config['FILE_UPLOADS'] = "C:\\Users\\Zachary\\Documents\\VSCode_Projects\\monday_webapp\\app\\static\\file\\uploads"

How can I make certain HTML not show up using Flask and Jinja2?

I'm making a Flask app that takes a single input from a user, and then uses that input to query an API, and return the results.
I'm trying to use the same template for both getting the user input, and displaying the results.
My return render template looks like this:
return render_template("query.html", json_data=json_data, info=info)
The problem is that when the page first loads, it's looking for the json_data, and info variables, but they don't exist yet.
I tried doing this:
data = request.args.get("t")
if data:
...
return render_template("query.html", json_data=json_data, info=info)
else:
return render_template("meter_mdm.html", json_data=None, info=None)
And then in my Jinja template, I put:
{% if json_data is not none and info is not none %}
...HTML that uses the json_data and info variables
{% endif %}
But it's still loading the data between the if statement.
Any idea what I need to do to load the results on the same page?
Try to simplify this line:
{% if json_data is not none and info is not none %}
to:
{% if json_data and info %}
Here is a worked demo:
view:
app.route('/')
def index():
name = None
age = None
return render_template('index.html', name=name, age=age)
index.html:
{% if name and age %}
Hello, boy!
{% endif %}

Running python script using html in Flask

I'm new to Flask and I'm trying to run a python script from background upon click on a button in a html page. Here is my code:
from flask import *
from functools import wraps
import sqlite3
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
#app.route('/generate')
def generate():
return render_template('process.html')
and my process.html is as follows:
<html>
<head>
<body>
Processing...
<script>
exec('python /pth to my python file/myfile.py')
</script>
</body>
</head>
</html>
and home.html is as follows:
{% extends "template.html" %}
{% block content %}
<div class = "jumbo">
<h2> Home</h2>
<br/>
<p>click me</p>
<p> lorem epsum </p>
<div>
{% endblock %}
I'm working on linux and I do not know whether it is possible to use exec in html as shown above. However exec command inside .html file is not executing. I'm still new to flask and I would appreaciate any suggestion on how to make it work.
The <script> tag in HTML is specifically for running client-side JavaScript code. Back-end logic should be done in the views. If you're just looking to execute a line of code that is present in myfile.py, you should put it in a function in that file and import it using from myfile import functionname or simply have that code present in the views (the latter being the proper way to do it in most cases). For example, if myfile.py contained print 'Hello World!' then your views should look like this:
from flask import *
from functools import wraps
import sqlite3
app = Flask(__name__)
#app.route('/')
def home():
return render_template('home.html')
#app.route('/generate')
def generate():
print 'Hello World!'
return render_template('process.html')
If you did it this way, you wouldn't have to split all of your code up into separate files. Unfortunately though, the template would be rendered after the code is executed, so 'Processing...' as shown in your process.html template would display after it has already been processed. As far as Flask goes, the best way that I'm aware of to show the user that the process took place would be to redirect back to the page and flash a message, like this:
#app.route('/generate')
def generate():
print 'Hello World!'
flash('Process complete!')
return redirect(url_for(home))
and then in home.html you would have something like this (from Flask 0.11 Documentation):
{% extends "template.html" %}
{% block content %}
<div class = "jumbo">
<h2> Home</h2>
<br/>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<p>click me</p>
<p> lorem epsum </p>
<div>
{% endblock %}
If you wanted something like 'Processing...' to display on the page, that's when you would want to use JavaScript.
Hopefully this helps :)

Flask 404 page not found

I'm writing a small application in Flask.
run.py
#!flask/bin/python
from app import app
app.run(debug=True, port=9001)
init.py
from flask import Flask
app = Flask(__name__)
from app import views
index.html
{% extends "base.html" %}
{% block content %}
<select id = "foo">
{% for item in Citydata %}
<option value = {{ item.link }}> {{ item.name }} </option>
{% endfor %}
</select>
Click here
{% endblock %}
new.html
{% extends "base.html" %}
{% block content %}
<p>gafgafgadfgaerwgtdfzgaergdfzgaergaergaergt</p>
{% endblock %}
and lastly views.py
from flask import render_template
from app import app
from bs4 import BeautifulSoup
import urllib2
import traceback
class City_Link(object):
name = ""
link = ""
# The class "constructor" - It's actually an initializer
def __init__(self, name, link):
self.name = name
self.link = link
#app.route('/')
#app.route('/index')
def index():
URL = 'http://www.amis.pk/DistrictCities.aspx'
City_Data = scrape(URL)
return render_template("index.html",
title='Home',
Citydata=City_Data)
#app.route('/new/<data>', methods=['GET', 'POST'])
def new(data):
return render_template("new.html",
title='Home',
link = data)
def scrape(url):
data = []
try:
page = urllib2.urlopen(url)
soup = BeautifulSoup(page.read(), "lxml")
table = soup.body.find(id='TABLE1')
for row in table.findAll("tr"):
heads = row.findAll("a")
for head in heads:
data.append((City_Link(head.text.strip(), head.attrs['href'])))
except:
print(traceback.format_exc())
return data
When i click on the "Click me" href in index.html It gives me a 404 not found on the template new.html. I dont understand why because I followed a basic tutorial. I tried changing ports and it worked. But then I tried to update the code and it broke the link again.
So the reason this happens is because flask registers /new and /new/ to be two different routes.
It also looks like you're not actually passing in any data to the data variable anyway. You can temporarily fix this issue by changing your link to point to
/new/something
But that doesn't totally address the problem. I recommend adjusting your template code to make use of flasks excellent url_for function. You can find the extended documentation for it here: http://flask.pocoo.org/docs/0.10/api/#flask.url_for
When we adjust your code, it should look like:
Click here
And that data variable looks like it's not even used! Let's just strip it out totally!
#app.route('/new', methods=['GET', 'POST'])
def new():
return render_template("new.html",
title='Home')
This has altered your code, and I may not have enough information about your use case. If this modifies it beyond being usable for your application, let me know and I'll adjust my answer accordingly.

Django: Use a variable from a view in a template

I want to use the content of a variable with the name "files" in my template in django. My views.py looks like this:
from django.shortcuts import render
import os
def index(request):
os.chdir("/home/ubuntu/newproject/static")
for files in os.listdir("."):
return render(request, 'sslcert/index.html','files')
And my template with the name "index.html" looks like this:
<head>
{% block title %}
<h3>
Following directories are in this folder:
</h3>
{% endblock %}
</head>
<body>
<<(HERE SHOULD BE THE OUTCOME OF THE VARIABLE LIST)>>
</body>
Help would be really cool and explanation too :/ I am a real beginner in django and I wish to know how this template and views stuff is connected :) please do not hate on me if this question is really stupid :(
You can pass variable to template like this:
from django.shortcuts import render_to_response
def index(request):
os.chdir("/home/ubuntu/newproject/static")
for file in os.listdir("."):
files.append(file)
return render_to_response('sslcert/index.html', {'files':files})
And in template you can use it like:
{{files}}
if you want to use whole field or you can loop through them
{% for file in files %}
# do something with file here
{% endfor %}
Do something like:
from django.shortcuts import render
import os
def index(request):
os.chdir("/home/ubuntu/newproject/static")
files = []
for file in os.listdir("."):
files.append(file)
context = {'files':files}
return render(request, 'sslcert/index.html', context)
and then the template:
<head>
{% block title %}
<h3>
Following directories are in this folder:
</h3>
{% endblock %}
</head>
<body>
{{ files }}
</body>
render function You are using in Your example got dictionary argument which can extend context passed into template
render(request, template_name[, dictionary][, context_instance][, content_type][, status][, current_app][, dirs])
dictionary
A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the view will call it just before rendering the template.
so you can pass any data into template as dictionary which keys will be available in template as variable
from django.shortcuts import render
def index(request):
dir = "/home/ubuntu/newproject/static"
return render('sslcert/index.html', {'files': os.listdir(dir)})

Categories

Resources