making a todo list using pickle and flask - python

i'm trying to make a simple todo list using flask and a text file database, for now I'm trying to add items and save it in a text file, and also show the items online, but I'm not sure what I'm going wrong,this is the code i have for now
from flask import Flask, render_template, request, redirect, url_for
import todo_list
app = Flask(__name__)
#app.route('/')
def index():
with open('programming.pkl', 'rb') as output:
new_list = todo_list.pickle.load(output)
return render_template('index.html', todo1=new_list, todo=todo )
#app.route('/task', methods=['GET''POST'])
def task():
if request.method == 'POST':
todo = request.form.get('todo')
with open('programming.pkl', 'wb+') as output:
todo_list.pickle.dump(todo, output)
return redirect('/')
and this is my HTML code, i have just used google.com as a place holder for now
<!DOCTYPE html>
<html>
<head>
<h1> TODO APP</h1>
</head>
<body>
<p>
<br>
<h2>Here are your todo items</h2>
</p>
<br>
<h3>{{ todo }}</h3>
<h4>Mark as done</h4>
<br>
<h3>{{ todo }}</h3>
<h4>Mark as done</h4>
<br>
<h3>stuff1</h3>
<h4>Mark as done</h4>
<br>
<form action="/task" method="POST">
<h3>Create todo</h3>
<input type="text" id="todo" name="todo"><br><br>
</form>
</body>
</html>

Related

jinja2.exceptions.UndefinedError: 'btn' is undefined

I am getting jinja2.exceptions.UndefinedError: 'btn' is undefined exception while logging to the localhost. The btn is properly defined but still.. Can I plaese get the help as soon as possible. Thank You in Advance
Python code- This code is the Python Code
from flask import Flask, render_template, request, send_file
from flask_sqlalchemy import SQLAlchemy
from send_email import send_email
from sqlalchemy.sql import func
from werkzeug import secure_filename
app=Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
#app.route("/success", methods=['POST'])
def success():
global file
if request.method=='POST':
file=request.files["file"]
file.save(secure_filename("uploaded" + file.filename))
with open("uploaded"+file.filename,"a") as f :
f.write("This was added later!")
return render_template("index.html", btn="download.html")
#app.route("/download")
def download():
return send_file("uploaded" + file.filename, attatchment_filename="yourfile.csv", as_attatchment=True)
if __name__ == '__main__':
app.debug=True
app.run()
HTML-
Index file - This is the main file
<!DOCTYPE html>
<html lang="en">
<title> Data Collector App</title>
<head>
<link href="../static/main.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Collecting Height</h1>
<h3>Please Fill the Entries to get Population Statistics on Height</h3>
<div class="message">
{{text | safe}}
</div>
<form action="{{url_for('success')}}" method="POST" enctype="multipart/form-data">
<input type="file" name="file" > <br>
<button type="submit">Submit</button>
</form>
{%include btn ignore missing%}
</div>
</body>
</html>
Download file- This is the html file for downloading. After importing the file this html code will create a button in the same index.html page so that I can also downoad the same file
<!DOCTYPE html>
<html lang="en">
<div class="download">
<button class="btn"> Download </button>
</div>
</html>
Was facing the same issue. My workaround was to replace:
{% include btn ignore missing %}
with
{% if btn %}
{% include btn %}
{% endif %}
This should work:
{% include [btn] ignore missing %}
The reason for change is due to a Flask update from the time when that video was created

jinja2.exceptions.TemplateNotFound why does this keep popping up?

This is my code pro.py which i have save in my Downloads:
from flask import Flask, render_template, flash, session, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'kmkey'
class SimpleForm(FlaskForm):
breed = StringField('What breed are you?')
submit= SubmitField('Click Me')
#app.route('/',methods=['GET','POST'])
def imp():
form = SimpleForm()
if form.validate_on_submit():
session['breed'] = form.breed.data
flash(f"You just changed your breed to: {session['breed']}")
return redirect(url_for('imp'))
return render_template('imp.html',form=form)
if __name__ == '__main__':
app.run(debug=True)
This is my html code imp.html which i have saved in my template folder which is inside Downloads:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
{% for mess in get_flashed_messages() %}
<div class="alert alert-warning alert-dismissible fade show" role='alert'>
<button type="button" class="fade close" data-dismiss='alert' aria-label='close' >
<span aria-hidden='true'>×</span>
</button>
{{mess}}
</div>
{% endfor %}
<form method="post">
{{form.hidden_tag()}}
{{form.breed.label}}{{form.breed}}
{{form.submit()}}
</form>
</body>
</html>
Now when i run my python file on web it throws an error saying that
jinja2.exceptions.TemplateNotFound:imp.html why does it happen like that??
Can anyone pls help me out with this issue.
You need to save it in templates folder not template folder.

Flask, Passing User Entered Data Between Views

Problem transferring variables across views I tried using sessions and could not get the connection to work. Say I have two pages, a home and page2. I have a flask app that will take user input from the home and print out input on page2.
For example, if you start my app, you will see this as the home page:
This part works fine, I am able to enter a value.
What I want to happen next, is after you click submit, page2 is generated showing what was just entered:
Whatever string value was entered on home should show up in the highlighted portion.
I have the following app.py file:
from flask import Flask, render_template, request, session
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def home():
stringval = ''
if request.method == 'POST' and 'stringval' in request.form:
stringval = request.form.get('stringval')
session["stringvalue_topass"] = stringval
return render_template('page2.html', stringval = stringval)
return render_template("home.html")
#app.route('/page2', methods=['GET', 'POST'])
def page2():
stringvalue_get = session.get('stringvalue_topass')
return render_template('page2.html', stringvalue_get = stringvalue_get)
if __name__ == '__main__':
app.run(debug=True)
The following home.html:
<!doctype html>
<h1>Enter Value </h1>
<div class="main">
<form class="pure-form" method="POST" action="/page2">
stringval:<br>
<input type="text" name="stringval"><br>
<button type="submit" class="pure-button pure-button-primary" value="Submit">Submit!</button>
</form>
</div>
</body>
And the following page2.html
<!doctype html>
<h1>You have selected </h1>
<div class="main">
{% if stringvalue_get %}
<pre>
{% print(stringvalue_get) %}
</pre>
{% endif %}
</div>
</body>
Okay, there are a few issues here. Firstly, the action attribute of your form in home.html is set to "/page2". This means that when the form is submitted, the POST request is going to the /page2 endpoint rather than to the /home endpoint, where you have written the code for handling the form submission. We can fix this by just deleting the action attribute, as this means the form will post to then endpoint that loaded it - in this case /home.
Secondly, Flask sessions cannot be used without setting a secret key to encrypt the session. This can be done by assigning a value to app.secret_key, like so:
app = Flask(__name__)
app.secret_key = b"my_secret_key"
Finally, instead of passing the string to the template like so: render_template('page2.html', stringval = stringval), (note also that this should be stringval_get = stringval), you can access the session object directly from templates already. So, in all, we can change your application code to:
app.py:
from flask import Flask, render_template, request, session
app = Flask(__name__)
app.secret_key = b"my_secret_key"
#app.route('/', methods=['GET', 'POST'])
def home():
if request.method == 'POST' and 'stringval' in request.form:
session["stringvalue_topass"] = request.form.get('stringval')
return render_template('page2.html')
return render_template("home.html")
#app.route('/page2', methods=['GET', 'POST'])
def page2():
return render_template('page2.html')
And your templates to:
home.html:
<!doctype html>
<h1>Enter Value </h1>
<div class="main">
<form class="pure-form" method="POST">
stringval:<br>
<input type="text" name="stringval"><br>
<button type="submit" class="pure-button pure-button-primary" value="Submit">Submit!</button>
</form>
</div>
</body>
page2.html:
<!doctype html>
<h1>You have selected </h1>
<div class="main">
{% if 'stringvalue_topass' in session %}
<pre>
{% print(session["stringvalue_topass"]) %}
</pre>
{% endif %}
</div>
</body>

Displaying a .txt file in my html using Python Flask

I want to display my log.txt in my log.html.
For some reason my page is completely blank.
And I dont get to see anything from my file.
Code:
def log():
with open("logs.txt", "r") as f:
content = f.read()
return render_template('log.html', content=content)
HTML LOG TEMPLATE:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Log</title>
<link rel="stylesheet" href="/static/styles/nav.css" />
<link rel="stylesheet" href="/static/styles/basiclayout.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<style>
</style>
<body>
<ul class="nav">
<li ><a href="{{ url_for('hello_world') }}" >Home</a></li>
<li >Notepad</li>
<li >Explorer </li>
<li class="active">Log </li>
<li >Upload </li>
<li >Uploads </li>
<li >Logout</li>
</ul>
<div class="alert">
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
</div>
<pre>{{ content }}</pre>
</body>
</html>
Added my HTML Template now.
return Response(content, mimetype='text/plain')
but really you probably want to use something like logstash...
Maybe it would be better if for the log to read the file backwards in order to access the last log first.
pip3 install file-read-backwards
For example, I will show this code backwards:
In your case, it is necessary to replace app.py with logs.txt
from flask import Flask, render_template
from file_read_backwards import FileReadBackwards
app = Flask(__name__, template_folder="template")
with FileReadBackwards("app.py") as f:
# getting lines by lines starting from the last line up
b_lines = [ row for row in f ]
#app.route('/', methods=["GET", "POST"])
def index():
return render_template('index.html', b_lines=b_lines)
if __name__ == "__main__":
app.run(debug=True)
UPDATE - without libraries
from flask import Flask, render_template
app = Flask(__name__, template_folder="template")
#app.route('/', methods=["GET", "POST"])
def index():
b_lines = [row for row in reversed(list(open("app.py")))]
return render_template('index.html', b_lines=b_lines)
if __name__ == "__main__":
app.run(debug=True)
Put in your log.html:
<br>
Description:
<br>
<textarea id="stackoverflow" name="stackoverflow_review" rows="35" cols="55">
{% for line in b_lines %}
{{ line }}
{% endfor %}
</textarea>
output:
In your case, the latest changes from the logs.txt file will be displayed first.
There are two files one being "file.py" and the respective HTML file being invoked from the templates folder.
import sys
from flask import Flask, render_template, redirect, url_for, request
app = Flask(__name__, template_folder="/root/templates")
def search():
with open("test","r") as file:
content = file.readlines()
print(content)
return render_template("file2.html", content = content)
if __name__ == "__main__":
app.run(debug=True)
File2.html:
Not sure how to attach HTML file. attaching a screen shot . Please refer

Flask-Sqlite posting to DB from webform

I have started just learning Flask and tried to find an answer how to post to SQLite DB from webform. So far haven't managed to get it work and bit lost with this. I manage to print values from DB based on code sample from simplypython but don't know how to add new ones from webform.
I would need to be able to address elements, open connection to the database, Insert values, save and close the connection. As far as I am aware I should add the POST method to the app.py and use request.form statement to pull the elements when submit button is pressed.
then the code should automatically display all the values on index html, which already works. could you please help me with the code I need to add to app.py file to get values added to DB and what to add to form action webform-section on html file?
index.html
<!DOCTYPE html>
<html>
<head>
<title>Flask Intro</title>
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
</head>
<body>
<div class="container">
<h3 potsit </h3>
{% for post in posts %}
Titleotsikko: {{post.title }} <br>
Postotsikko: {{post.description}}
{% endfor %}
</div>
<div>
<form action="/????????????NOT SURE WHERE TO DIRECT" method="post">
<div>
<label for="title">title:</label>
<input type="text" id="title" />
</div>
<div>
<label for="description">description:</label>
<input type="text" id="description" />
</div>
<div class="button">
<button type="submit">Add to db</button>
</div>
</form>
</div>
</body>
</html>
app.py
from flask import Flask, render_template, request, session, g
import sqlite3
app = Flask(__name__)
#app.route('/')
def home():
g.db = sqlite3.connect("sample.db")
cur = g.db.execute('select * from posts')
posts = [dict(title=row[0], description=row[1]) for row in cur.fetchall()]
g.db.close()
return render_template("index.html", posts=posts)
if __name__=='__main__':
app.run(debug=True)
sql.py
import sqlite3
with sqlite3.connect("sample.db") as connection:
c = connection.cursor()
c.execute("DROP TABLE posts")
c.execute("CREATE TABLE posts(title TEXT, description TEXT)")
c.execute('INSERT INTO posts VALUES("Luck", "no luck.")')
EDIT
I made some changes based on the suggestion from Paul Rooney and created file called post.html, moved the form there from index.htmland added another #route on the app.py file. I believe I'm not far off but after trying to figure this out since Tuesday hoping to get it work. Unfortunately now I receive an error 405 'The method is not allowed for the requested URL.' and I'm stuck with this after trying different options.
post.html
<!DOCTYPE html>
<html>
<head>
<title>Flask post</title>
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
</head>
<body
<div>
<form action="/post" method="post">
<div>
<label for="title">title:</label>
<input type="text" id="title" />
</div>
<div>
<label for="description">description:</label>
<input type="text" id="description" />
</div>
<div class="button">
<button type="submit">Add to db</button>
</div>
</form>
</div>
</body>
</html>
(edited) app.py
from flask import Flask, render_template, request, session, g, redirect, url_for
import sqlite3
app = Flask(__name__)
#app.route('/')
def home():
g.db = sqlite3.connect("sample.db")
cur = g.db.execute('select * from posts')
posts = [dict(title=row[0], description=row[1]) for row in cur.fetchall()]
g.db.close()
return render_template("index.html", posts=posts)
#app.route('/post', methods=['POST'])
def post():
title=request.form['title']
description=request.form['description']
print title, description
return redirect(url_for('/'))
if __name__=='__main__':
app.run(debug=True)
To answer your original question you should pick an endpoint to post your data to and use that in both your flask app and the html form action.
I suggested post in comments but it could be anything. I think you've grasped what to do here but for completeness.
The HTML
<form action="/post" method="post">
The Python Code
Add a route to handle the POSTed data.
#app.route('/post', methods=['POST'])
def post():
# Do db stuff then redirect back to index page.
pass
Edited Question
You have an indentation error in your code, which is causing the 405 error. Your post function is inside your home function. Make it more like this
app.py
from flask import Flask, render_template, request, session, g, redirect, url_for
import sqlite3
app = Flask(__name__)
#app.route('/')
def home():
g.db = sqlite3.connect("sample.db")
cur = g.db.execute('select * from posts')
posts = [dict(title=row[0], description=row[1]) for row in cur.fetchall()]
g.db.close()
return render_template("index.html", posts=posts)
# One level of indentation removed from here downwards
#app.route('/post', methods=['POST'])
def post():
title=request.form['title']
description=request.form['description']
return redirect(url_for('home'))
if __name__=='__main__':
app.run(debug=True)
After that I see a 400 Bad Request error, which stems from the fact that you don't have name parameters in your html form.
The attempt to access the title and description values in the form dict in app.py will throw a KeyError exception, as those keys will not be present without the name parameter in the html.
If you add them e.g.
...
<input type="text" id="title" name='title'/>
...
<input type="text" id="description" name='description'/>
...
Then it will run all the way through your function.
The next issue will be
redirect(url_for('/'))
instead use
redirect(url_for('home'))
home being the name of the function called for path '/'.
After that you should be good to go.

Categories