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.
Related
This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
Closed 1 year ago.
So I got a delete route to delete data from SQL. How do I get the id from HTML so I can Delete the data from application.py using db.execute("DELETE FROM birthdays WHERE name=?",id)
Delete method reference:https://www.digitalocean.com/community/tutorials/how-to-modify-items-in-a-one-to-many-database-relationships-with-flask-and-sqlite
This is my code:
application.py:
import os
from cs50 import SQL
from flask import Flask, flash, jsonify, redirect, render_template, request, session
# Configure application
app = Flask(__name__)
# Ensure templates are auto-reloaded
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Configure CS50 Library to use SQLite database
db = SQL("sqlite:///birthdays.db")
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
# TODO: Add the user's entry into the database
name = request.form.get("name")
month = request.form.get("month")
date = request.form.get("date")
if not name or month or date :
return render_template("error.html", message="Missing something")
db.execute("INSERT INTO birthdays (name,month,day) VALUES(?,?,?)",name,month,date)
return redirect("/")
else:
# TODO: Display the entries in the database on index.html
entries=db.execute("SELECT * FROM birthdays" )
return render_template("index.html",entries=entries)
#FIX HERE
#app.route("/delete", methods=["GET", "POST"])
def delete(id):
if request.method == "post":
db.execute("DELETE FROM birthdays WHERE name=?",id)
return redirect("/")
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght#500&display=swap" rel="stylesheet">
<link href="/static/styles.css" rel="stylesheet">
<title>Birthdays</title>
</head>
<body>
<div class="jumbotron">
<h1>Birthdays</h1>
</div>
<div class="container">
<div class="section">
<h2>Add a Birthday</h2>
<!-- TODO: Create a form for users to submit a name, a month, and a day -->
<form action="/" method="post">
<input autocomplete="off" type="text" name="name" placeholder="Name">
<input autocomplete="off" type="number"min=1 max=12 name="month" placeholder="month">
<input autocomplete="off" type="number"min=1 max=31 name="date" placeholder="date">
<input type="submit" value="submit">
</form>
</div>
<div class="section">
<h2>All Birthdays</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Birthday</th>
</tr>
</thead>
<tbody>
<!-- TODO: Loop through the database entries to display them in this table -->
{% for person in entries%}
<tr>
<td>{{person.name}}</td>
<td>{{person.day}}/{{person.month}}</td>
<!--DELETE BUTTON-->
<td><form action="{{ url_for('delete', id=person.name) }}" method='post'><input type="submit" value="delete"></form></td>
</tr>
{% endfor%}
</tbody>
</table>
</div>
</div>
</body>
</html>
For the delete route, you need to add the id variable:
#FIX HERE
#app.route('/<int:id>/delete/', methods=('POST',))
def delete(id):
https://flask.palletsprojects.com/en/1.1.x/quickstart/#variable-rules
I just start learning Flask and i'm trying to use a simple search form on my news headline site but when i submit the search it seems that it's not working, i'm using a simple flask get request
Here is my code:
import feedparser
from flask import Flask
from flask import render_template
from flask import request
app = Flask(__name__)
rss_feed = {'wsj': "https://feeds.a.dj.com/rss/RSSWSJD.xml",
'cnbc': "https://www.cnbc.com/id/100003114/device/rss/rss.html",
'washington_post': "http://feeds.washingtonpost.com/rss/politics?itid=lk_inline_manual_2"}
#app.route("/")
def get_news():
query = request.args.get('publication')
if not query or query.lower not in rss_feed:
publication = 'wsj'
else:
publication = query.lower
feed = feedparser.parse(rss_feed[publication])
return render_template("home.html", articles=feed['entries'])
if __name__ == "__main__":
app.run(port=5000, debug=True)
and my html code:
<html>
<head>
<title>Headlines</title>
</head>
<body>
<h1>Headlines</h1>
<form>
<input type="text" name="publication" placeholder="search">
<input type="submit" value="Submit">
</form>
{% for article in articles %}
<b>{{article.title}}</b><br />
<i>{{ article.published }}</i><br />
<p>{{ article.summary }}</p>
<hr />
{% endfor %}
</body>
</html>
Now when i submit a search for 'cnbc' it still display the result for 'wsj' what wrong with my code?
I add 4 different notes in the code as comment, please have a look in the Glossary.
Here is the solution:
Python file, here is where the error occur, long stoyry short your if statement was always returning True, hence the publication variable was set as 'wsj
import feedparser
from flask import render_template, request, Flask
# Note 1
app = Flask(__name__)
rss_feed = {'wsj': "https://feeds.a.dj.com/rss/RSSWSJD.xml",
'cnbc': "https://www.cnbc.com/id/100003114/device/rss/rss.html",
'washington_post': "http://feeds.washingtonpost.com/rss/politics?itid=lk_inline_manual_2"}
#app.route("/")
def get_news():
if request.args.get('publication'):
query = request.args.get('publication').lower() # Note 2
print(f'Query is : {query}') # Note 4
if not query or query not in rss_feed: # Note 3
print('Publication is wsj') # Note 4
publication = 'wsj'
else:
print('Publication is the query entry') # Note 4
publication = query
feed = feedparser.parse(rss_feed[publication])
return render_template("view.html", articles=feed['entries'])
return render_template("view.html")
if __name__ == "__main__":
app.run(port=5000, debug=True)
HTML File
<html>
<head>
<title>Headlines</title>
</head>
<body>
<h1>Headlines</h1>
<!-- Note 5 -->
<form method="GET">
<input type="text" name="publication" placeholder="search">
<input type="submit" value="Submit">
</form>
{% for article in articles %}
<b>{{article.title}}</b><br />
<i>{{ article.published }}</i><br />
<p>{{ article.summary }}</p>
<hr />
{% endfor %}
</body>
</html>
NOTES GLOSSARY
Note 1: Have the imports from the same package in the same line
Note 2: Rather then check the query if is lower is better to turn it lower already in the variable as I did.
Note 3: Here is where the real issue was. This statement was always True hence setting the 'publication' variable as 'wsj'. This is because of add 'query.lower' not in rss_feed which obsiously it wasn't. And by the way you should have done it 'query.lower()'
Note 4: Just a reminder to How to find and troubleshot your code.The print() function is the first thing to learn in python and is the most usefull tool for this matter. This is how I found the error in less then 5 minutes because I let the code 'Speak' through the terminal.
Note 5: Few suggestion here, first add a method='GET' (not neccessary) just for readability. Then indent better the HTML file as it was all messed around.
Another solution that may be slightly clearer is this:
#app.route("/")
def get_news():
if request.args.get('publication'):
query = request.args.get('publication').lower()
if not query or query not in rss_feed:
publication = 'wsj'
feed = feedparser.parse(rss_feed[publication])
return render_template("view.html", articles=feed['entries'])
publication = query
feed = feedparser.parse(rss_feed[publication])
return render_template("view.html", articles=feed['entries'])
return render_template("view.html")
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>
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>
I am new to web development. I am trying to create a web page which will display index from elastic search database. I am using python flask for backend.
I see html page and python console shows index.
But I am not able to fetch index from HTML page.
I am not sure what could be the issue
Python code is as follows:
from flask import Flask,render_template, request
from elasticsearch import Elasticsearch
app = Flask(__name__)
es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
doc1 = {"food": "Japanese", "spice_level": "moderate"}
doc2 = {"food": "Italian", "spice_level": "mild"}
doc3 = {"food": "Indian", "spice_level": "spicy"}
es.index(index="food", doc_type="spice_level", id=1, body=doc2)
resp = es.get(index="food", doc_type="spice_level", id=1)
print(resp)
#app.route('/')
def home():
return render_template('index.html')
app.route('/dashboard', methods=['GET', 'POST'])
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
HTML code is as follows:
<!DOCTYPE html>
<BODY bgcolor="cyan">
<form method="GET" action="/dashboard">
<center>
<H1>Database UI </H1> <br>
search here <input type = "text" name= "index" /> <br>
<input type = "submit">
</center>
</form>
</BODY>
</html>
Whenever I type a index name and click on search button, page gives me error as :
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
I cannot see any other error then this, and it's really difficult to debug with less information about error.
why your /dashboard return 404 ?
because lack of view function to response.
app.route('/dashboard', methods=['GET', 'POST']) is invalid.
How to access /dashboard of elascticsearch ?
In your case, the simplest way is modify the index.html
<!DOCTYPE html>
<BODY bgcolor="cyan">
<form method="POST" action="http://localhost:9200/dashboard">
<center>
<H1>Database UI </H1> <br>
search here <input type = "text" name= "index" /> <br>
<input type = "submit">
</center>
</form>
</BODY>
</html>
can you use this here? for Parse data from html to python code you need to have POST inside #app.route like this:
#app.route("/", methods=['GET', 'POST'])
def home():
return render_template('index.html')
if you want to pase data into index.html you can use this here:
somedata = "variable string"
render_template('index.html', somedata=somedata)
inside index.html do {{ somedata }}
<!DOCTYPE html>
<BODY bgcolor="cyan">
<form method="POST" action="">
<center>
<H1>Database UI </H1> <br>
<!-- it will show (variable string) -->
{{ somedata }}
search here <input type = "text" name= "index" /> <br>
<input type = "submit">
</center>
</form>
</BODY>
</html>
happy codeing.