Hi I am trying to create a customer feedback form; I have managed to create the pages I need, but I am having difficulty connecting my app to my SQLite3 database.
So in my code python code I am trying to collect the data from the customer feedback form and hold it in a database.
In the feedback form they will be prompted to input their name, choose some answers from a drop-box selection, and to write a comment at the end.
The answers will be housed in the database (for future reference - like reports etc) and the user will be redirected back to the home page where they will be able to see their name & comment (taken from the feedback form).
I have watched tutorials on sqlite3 which was kind of easy to understand & execute (a lot easier for me than MySQL) but I'm missing something because it won't connect to my database.
my python flask code:
from flask import Flask, render_template, redirect, url_for, request, session, flash, g
from functools import wraps
import sqlite3
app = Flask(__name__)
app.secret_key = "random_character_generator" # this would be random or anything the developer wants
app.database = "gymdatabase.db"
conn = sqlite3.connect(app.database)
c = conn.cursor()
def connect_db():
return sqlite3.connect(app.database)
#app.route('/')
def home():
g.db = connect_db()
cur = g.db.execute('select * from posts')
posts = [dict(name=row[0], welcome=row[1], equipment=row[2], cleanliness=row[3], interaction=row[4], comments=row[5], contact=row[6]) for row in cur.fetchall()]
g.db.close()
return render_template('gym_index.html', posts=posts)
#app.route('/feedback', methods=['POST'])
def feedback():
return render_template('gym_feedback.html')
#app.route('/process', methods=['GET', 'POST'])
def process():
g.db = connect_db()
name = request.form['name']
welcome = request.form['welcome']
equipment = request.form['equipment']
cleanliness = request.form['cleanliness']
interaction = request.form['interaction']
comment = request.form['comment']
contact = request.form['yes_no']
conn.commit()
cur = g.db.execute(select * from posts)
posts = [dict(name=row[0], welcome=row[1], equipment=row[2], cleanliness=row[3], interaction=row[4], comments=row[5], contact=row[6]) for row in cur.fetchall()]
g.db.close()
return redirect(url_for('home', posts=posts))
When I try to submit a feedback form I get:
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.
I can upload the html file on request; I'm not too sure if I have space to do so along with my python file.
I think that this is due to your line conn.commit() in your process() function. You declare conn = sqlite3.connect(app.database) when Flask first starts, but each function defined with the #app.route(...) function decorator gets called in a different thread in response to HTTP requests (as defined in the aforementioned function decorator). You probably want to do something like this:
#app.route('/process', methods=['GET', 'POST'])
def process():
...
db = connect_db()
cur = db.cursor()
cur.execute("select * from posts")
results = cur.fetchall()
...
You can see this link for further documentation: https://docs.python.org/2/library/sqlite3.html
I can edit my answer if you provide more context regarding where your code is failing.
Related
I have this code(not complete)
#app.route('/', methods = ['GET','POST'])
def home():
"""
the main function for routing home
"""
if request.method == 'POST':
try:
if not cursor:
cursor = mysql.connection.cursor()
url = request.form.get('link',"")
the thing is i have to re declare cursor every time inside request.method=='POST' block
if i declare it outside(say first line) i got an error saying cursor not defined.because the post connection is not active yet
In Flask, you can use the before_request decorator to create a cursor
only once and reuse it in multiple routes. Here's an example: In this
example, the cursor is created using mysql.connection in the
before_request function, which runs before each request. The cursor is
then stored in g (the Flask global request object), so it can be
reused in multiple routes. The teardown_request function closes the
cursor and the connection after each request.
from flask import Flask
from flask_mysqldb import MySQL
app = Flask(__name__)
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'user'
app.config['MYSQL_PASSWORD'] = 'password'
app.config['MYSQL_DB'] = 'database'
mysql = MySQL(app)
#app.before_request
def before_request():
g.conn = mysql.connection
g.cursor = g.conn.cursor()
#app.teardown_request
def teardown_request(exception):
if hasattr(g, 'cursor'):
g.cursor.close()
if hasattr(g, 'conn'):
g.conn.close()
#app.route('/')
def index():
g.cursor.execute('SELECT * FROM table')
data = g.cursor.fetchall()
return data
I am trying to do a GET request which should print a specific row from my database depending on what arguments are set. The argument should be a name of a course and I want it to get all data from the selected course. It might be a bit easier to explain this as a SQL query. The query could look like this "SELECT * FROM courselist WHERE course='D0024E';"
where "course".
I have managed to do a fetchall() and receive all rows from a specific table, but I have not managed to get the parameters working correctly so I can get information from a specific course.
from flask import Flask
from flask import render_template
import requests
from flask import request
from flask import jsonify
import mysql.connector
app = Flask(__name__)
mydb = mysql.connector.connect(user='Mille',
auth_plugin='mysql_native_password',
password='jagheter12',
host='localhost',
database='paraplyet')
#app.route('/')
def index():
return render_template("index2.html")
#app.route('/courses', methods= ["GET"])
def getStudentInCourse():
myCursor2 = mydb.cursor()
query2 = ("SELECT * FROM paraplyet.kursinfo")
myCursor2.execute(query2)
myresult2 = myCursor2.fetchall()
return jsonify(myresult2)
if __name__ == '__main__':
app.run()
You need to update your route url to receive parameters
#app.route('/courses/<course_code>', methods= ["GET"])
def getStudentInCourse(course_code):
Then you can use this course_code to filter result.
Actually there are several points where your code(s) can fail, because establishing a correct front-end back-end chain in Flask is a little tricky (but worth it at the end).
You have a counter part front-end HTML code where you start your request with the proper variable, like "course" in your example, which may looks like this:
<form action="/courses" method="post">
<input>
<button type="submit"></button>
</form>
Then Flask as back-end will get this variable(parameter) as part of your query string as part of the URL string. You can retrieve this parameter in the form:
course = request.form.get('course')
To achieve it you have to add "POST" the view's methods, as it handles only "GET"-s as default.
#app.route('/courses', methods=["GET", "POST"])
Then you can use this variable as you want to complete your back-end operations:
query2 = ("SELECT * FROM courseInfo where courseCode = '" + course + "';")
those results then you can pass it back to the front-end via:
return jsonify(myresult2)
Your python/flask code should be some like as follows:
from flask import Flask
from flask import render_template
import requests
from flask import request
from flask import jsonify
import mysql.connector
app = Flask(__name__)
mydb = mysql.connector.connect(user='Mille',
auth_plugin='mysql_native_password',
password='jagheter12',
host='localhost',
database='paraplyet')
#app.route('/')
def index():
return render_template("index2.html")
#app.route('/courses', methods= ["GET", "POST"])
def getStudentInCourse():
if request.method == "POST" and request.form.get('course') != '':
myCursor2 = mydb.cursor()
course = request.form.get('course')
query2 = ("SELECT * FROM courseInfo where courseCode = '" + course + "';")
myresult2 = myCursor2.execute(query2)
return jsonify(myresult2)
if __name__ == '__main__':
app.run()
I have a Flask website with a MySQL backend. I have a table called, users. It has two columns: username and name and one record:
name username
Jim testuser123
When a user clicks the button on the website, it updates the record to set the name to Bob then print all records where name = 'Bob'. Yet, it returns no results. If I refresh the connection before re-querying, then it does return one result as it should. Does the mdb.connect object cache data? How could it not be returning the correct results?
init.py:
import pandas as pd
import MySQLdb as mdb
from flask import Flask, render_template, request
def sql_con():
return mdb.connect(host='myhost', port=3306, user='root', passwd='root', db='db', use_unicode=True, charset="utf8")
app = Flask(__name__)
def update_record():
con = sql_con()
cur = con.cursor()
sql_string= "Update users set name = 'Bob' where username = 'testuser123'"
cur.execute(sql_string)
con.commit()
#app.route('/', methods=['GET', 'POST'])
def myroute():
con = sql_con()
if request.method == 'POST':
update_record()
print pd.read_sql("select * from users where name = 'Bob'", con=con)
return render_template('1.html')
app.run( debug=True, port=5050)
1.html
<html>
<body>
<form method="POST">
<button id="mybutton" name='btn' value="mybutton">Submit Data</button>
</form>
</body>
For this code to print one result, I must add con=sql_con() right after I call the update(), but before the print statement. Why is that?
In general it is a good practice to use an ORM binding (i.e. Falsk-SQLAlchemy) with web frameworks (manages connection pools, automates commit/rollback, ...) even if an ORM seems overkill for a simple application.
Otherwise, avoid using multiple connections to the same database in the same request if you prefer manage this at low level (database connections).
Try this instead:
import pandas as pd
import MySQLdb as mdb
from flask import Flask, render_template, request
def sql_con():
return mdb.connect(host='myhost', port=3306, user='root', passwd='root', db='db', use_unicode=True, charset="utf8")
app = Flask(__name__)
def update_record(con):
cur = con.cursor()
sql_string= "Update users set name = 'Bob' where username = 'testuser123'"
cur.execute(sql_string)
con.commit()
#app.route('/', methods=['GET', 'POST'])
def myroute():
con = sql_con()
if request.method == 'POST':
update_record(con)
print pd.read_sql("select * from users where name = 'Bob'", con=con)
return render_template('1.html')
app.run( debug=True, port=5050)
If you want to scale a real app based on such solution, you should consider pulling an opened connection from a global connections pool. Creating a new db connection (at each HTTP request) may be time expensive.
I have a heroku app that I am trying to add a database to. I am using Flask-SLAlchemy, PostgreSQL (and psql). I've already created a table in the database, but I cannot add any rows to it. Here is what I believe to be all relevant code:
import flask
import keys
import requests_oauthlib
import json
import os
import psycopg2
import urlparse
from flask import (Flask, jsonify, render_template, redirect, url_for, request, make_response)
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'heroku-url-here'
db = SQLAlchemy(app)
class Page (db.Model):
__tablename__ = "pages"
title = db.Column('Title', db.String)
date = db.Column('Date', db.String, primary_key=True)
writing = db.Column('Writing', db.String)
def __init__(self, title, date, writing):
self.title = title
self.date = date
self.writing = writing
def __repr__(self):
return '<Page %r>' % self.date
app.secret_key = keys.secret_key
# db.create_all()
# this created the database already after I ran it once, it made a psycopg2 error after that first time.
#app.route('/db', methods=['GET', 'POST'])
def db():
if request.method == 'POST':
title = request.form['title']
date = request.form['date']
writing = request.form['writing']
newest = Page(title, date, writing)
print newest
db.session.add(newest)
db.session.commit()
else:
title = None
date = None
writing = None
return flask.redirect(flask.url_for('home'))
In my heroku logs, there are no errors shown. The code runs to the the print newest line, and the newly created Page is printed as <Page u'whatever-the-date-was'>. When a form is submitted in my html template, it calls the function by using the action {{url_for('db')}}.
This is my first time using heroku and flask and basically doing any back-end stuff, so please explain thoroughly if you have an answer. Thanks in advance!
Take advantage of your Page model here.
db.session.add(Page(
title = request.form['title']
date = request.form['date']
writing = request.form['writing']
))
db.session.commit()
You'll probably also run into trouble with your conditional - if the method isn't POST then nothing will happen, and there won't be any message logged about it. If you remove the 'GET' from the methods in the route declaration you won't need that conditional at all.
I'd recommend taking a look at the Flask-WTF extension, as well as breaking out your form validation and redirect steps into separate functions. Flask works best by breaking down elements to their smallest usable components and then reassembling them in many different ways.
For more info on form handling, check out Miguel Grinberg's Flask Mega-Tutorial (if you haven't already).
I am building a simple web-app which uses existing MySQL DB. It is my first time using Flask and I have been struggling to understand what I am doing wrong for the past couple of hours.
My simple project structure:
/root
/app
__init__.py
db.py
forms.py
views.py
/templates
base.html
index.html
login.html
config.py
run.py
I am trying to query my MySQL DB and fill the template with the result from the query.
My db.py:
from app import app
from flaskext.mysql import MySQL
class DB(object):
mysql = MySQL()
def __init__(self):
app.config['MYSQL_DATABASE_USER'] = 'loguser'
app.config['MYSQL_DATABASE_PASSWORD'] = 'asdzxc'
app.config['MYSQL_DATABASE_DB'] = 'log'
app.config['MYSQL_DATABASE_HOST'] = '127.0.0.1'
app.config['MYSQL_DATABASE_PORT'] = 33006
self.mysql.init_app(app)
def query_db(self):
cursor = self.mysql.connect().cursor()
cursor.execute("SELECT name from users limit 1")
data = cursor.fetchone()
if data is None:
return "No results from query"
else:
return data
And in my views.py I have the following:
from flask import render_template, flash, redirect
from app import app
from .forms import LoginForm
from .db import DB
#app.route('/')
#app.route('/index')
def index():
db = DB()
user = db.query_db()
print(user) (it prints it here so the db connection works)
posts = [ # fake array of posts
{
'author': {'nickname': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'nickname': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template("index.html",
title='Home',
user=user,
posts=posts)
I get "AssertionError" when I try to assign "user" to the user from the template:
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
I believe I am violating a major principle of the framework. What is the correct way to pass the data to the template?
It is better to use Flask-SQLAlchemy and MySQL-python 1.2 , Successful code and documentation is available on the link below.
http://techarena51.com/index.php/flask-sqlalchemy-tutorial/
From my experience I found that MySQl support is not that good for python 3 atleast, it is better to use PostgreSQL, but that's just my personal opinion.
It's very late to give answer, but it may help someone.
You've to connect to MySQL before adding any route source to an API.
It should be in the order of
# 1. MySQL setup should be done at first
app = Flask(__name__)
api = Api(app)
mysql = MySQL()
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'DataBase'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
conn = mysql.connect()
cursor = conn.cursor()
# 2. Create API resource after that
api.add_resource(CreateUser, '/CreateUser')