Flask-SLAlchemy session.add() and session.commit() don't work - python

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).

Related

Flask_sqlalchemy, engine, session, connection and running SQL in my Flask app

I am beyond confused at this point. I have read so much documentation and there seems to be sparse examples of what to do for running raw SQL statements on my flask app using Flask_sqlalchemy or flask_mysqldb.
I have started by downloading XAMPP and creating a database on MySQL server through my localhost. I then created my flask application and created an initial database from the terminal using
>>> from yourapplication import db
>>> db.create_all()
The code from my flask app is as follows based on the documentation here
from flask import Flask, render_template, request, redirect, session
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from werkzeug.security import check_password_hash, generate_password_hash
# Set up Flask instance
app = Flask(__name__)
# Configure db
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root#localhost/hoook"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
# Reload templates when changed (take down when in production)
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Create db model
class Users(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Text, nullable=False)
last_name = db.Column(db.Text, nullable=False)
email = db.Column(db.Text, unique=True, nullable=False)
password = db.Column(db.Text, nullable=False)
date = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return "<Users %r>" % self.id
great, now I can see my table in myPhpAdmin. I then ran a test statement to see if information would be added as follows
db.engine.execute("INSERT INTO users (first_name, last_name, email, password) VALUES ('chris', 'blah', 'blah#gmail.com', 'something')")
works! but then looking at the previous stackoverflow answer and then the subsequent documentation I find this method is depreciated therefore I cant use this going forward. So I try to use session.execute instead (since connection.execute also shows its depreciated) as I see that for some reason there are three different methods all with the same function execute() that can be used...???? source. So using the following statement I try to add another row to my table but it failed.
db.session.execute("INSERT INTO users (first_name, last_name, email, password) VALUES ('jeremy', 'blah', 'something#gmail.com', 'whatever')")
there were no error messages, just when I check my database, nothing new was added. So if I got this right engine.execute didnt need a connection but session does? Does that mean this line
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root#localhost/hoook"
is actually not connecting the session method to my database then? What about the pymysql connector in the URI? do I also need to import pymysql to be able to use this connector? What is the correct method for generating queries and being able to add tables etc from within your flask app... Please clarify as this is confusing and from my point of view, all this documentation and abstraction needs to be cleaned up.

Python Flask SQLAlchemy check if database is available

before rendering the template I want to check if the database that I am using is available. The database is only available with specific IP, therefore, if someone tries to access the page, I don't want to error everything out, but redirect to a different template without the need for a database.
The error message:
(2003, "Can't connect to MySQL server on 'db-test' (110)")
(Background on this error at: https://sqlalche.me/e/14/e3q8)
There is no issue with the error itself, I just want to be able to check if the database is accessible without waiting until the error occurs while loading the page.
storage.py:
from flask_sqlalchemy import SQLAlchemy
db_req = SQLAlchemy()
class Requests(db_req.Model):
__tablename__ = 'requests'
id = db_req.Column(db_req.Integer, primary_key=True, nullable=False)
created = db_req.Column(db_req.DateTime, nullable=False)
name = db_req.Column(db_req.String, nullable=False)
app.py:
from flask import Flask
from models import db_req
from views.requests import requests
app = Flask(__name__)
app.register_blueprint(requests)
app.config.from_object("config.Config")
db_req.init_app(app)
if __name__ == '__main__':
app.run(debug=True)
requests.py:
from flask import Blueprint, render_template, request
from query_request_db import get_fields
requests = Blueprint("requests", __name__)
#requests.route("/", methods=["GET", "POST"])
def requests_page():
# need to check before everything if I can access database not to error out
return render_template("requests_page.html", names=get_fields.get_field_data("name"))
I am trying to find a way to check if the database is available without erroring out. Any help is welcome!
Hope I understand you right? that u want to check ip Addresse of the viewer of your Page.
Then u can use
request.remote_addr
to validate the IP Adress that has access to database ohterwise just do a redirect.

How can I connect my flask app to my SQLite3 database?

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.

how to give structure to python flask application

I am new to python flask
Experimenting some end points with MongoDB as shown below in a single file
from flask import Flask, request
from flask.ext.mongoalchemy import MongoAlchemy
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['MONGOALCHEMY_DATABASE'] = 'library'
db = MongoAlchemy(app)
class Author(db.Document):
name = db.StringField()
class Book(db.Document):
title = db.StringField()
author = db.DocumentField(Author)
year = db.IntField();
#app.route('/author/new')
def new_author():
"""Creates a new author by a giving name (via GET parameter)
e.g.: GET /author/new?name=Francisco creates a author named Francisco
"""
author = Author(name=request.args.get('name', ''))
author.save()
return 'Saved :)'
#app.route('/authors/')
def list_authors():
"""List all authors.
e.g.: GET /authors"""
authors = Author.query.all()
content = '<p>Authors:</p>'
for author in authors:
content += '<p>%s</p>' % author.name
return content
if __name__ == '__main__':
app.run()
Above code which contains two end points to post and get the data which is working fine
Know looking for a way to separate the code into different file like
the database connection related code should be in different file
from flask import Flask, request
from flask.ext.mongoalchemy import MongoAlchemy
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['MONGOALCHEMY_DATABASE'] = 'library'
db = MongoAlchemy(app)
I should be able to get the DB reference in different files where the schema is define and use it
class Author(db.Document):
name = db.StringField()
class Book(db.Document):
title = db.StringField()
author = db.DocumentField(Author)
year = db.IntField();
and routes will be different file
#app.route('/author/new')
def new_author():
"""Creates a new author by a giving name (via GET parameter)
e.g.: GET /author/new?name=Francisco creates a author named Francisco
"""
author = Author(name=request.args.get('name', ''))
author.save()
return 'Saved :)'
#app.route('/authors/')
def list_authors():
"""List all authors.
e.g.: GET /authors"""
authors = Author.query.all()
content = '<p>Authors:</p>'
for author in authors:
content += '<p>%s</p>' % author.name
return content
Here in the endpoints file i should get the reference of database schema please help me in getting this structure
Point me to some understandable sample or video which can help me to do,I am new to python as well as flask please point some sample and help to learn more thanks
A basic structure could look like this:
/yourapp
/run.py
/config.py
/yourapp
/__init__.py
/views.py
/models.py
/static/
/main.css
/templates/
/base.html
/requirements.txt
/venv
Applied to your example it would look like this.
run.py: Start your application.
from yourapp import create_app
app = create_app()
if __name__ == '__main__':
app.run()
config.py: Contains configuration, you could add subclasses to differentiate between Development config, Test config and Production config
class Config:
DEBUG = True
MONGOALCHEMY_DATABASE = 'library'
yourapp/_init_.py: Initialization of your application creating a Flask instance. (Also makes your app a package).
from flask import Flask
from flask.ext.mongoalchemy import MongoAlchemy
from config import Config
db = MongoAlchemy()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
from views import author_bp
app.register_blueprint(author_bp)
return app
yourapp/models.py: Contains your different models.
from . import db
class Author(db.Document):
name = db.StringField()
class Book(db.Document):
title = db.StringField()
author = db.DocumentField(Author)
year = db.IntField();
yourapp/views.py: Also called the routes.py sometimes. contains your url endpoints and the associated behavior.
from flask import Blueprint
from .models import Author
author_bp = Blueprint('author', __name__)
#author_bp.route('/author/new')
def new_author():
"""Creates a new author by a giving name (via GET parameter)
e.g.: GET /author/new?name=Francisco creates a author named Francisco
"""
author = Author(name=request.args.get('name', ''))
author.save()
return 'Saved :)'
#author_bp.route('/authors/')
def list_authors():
"""List all authors.
e.g.: GET /authors"""
authors = Author.query.all()
content = '<p>Authors:</p>'
for author in authors:
content += '<p>%s</p>' % author.name
return content
yourapp/static/... Contains your static files.
yourapp/templates/.. Contains your templates.
requirements.txt has a snapshot of your package dependencies.
venv (Virtualenv) folder where your python libs are to be able to work in a contained environment.
References:
Have a look at this related question.
Good example of a widely used project structure.

Access to session in flask_wtf

In forms.py I wanna get access to sessions.
this is forms.py code:
from flask_wtf import Form
from wtforms import SelectField,FileField,TextAreaField,TextField,validators
.
.
.
class Send(Form):
group = SelectField('Group',[validators.Required('you must select a group')],coerce=int,choices=c)
title = TextField('Title',[validators.Required('you must enter a title')])
content = TextAreaField('Content',[validators.Required('you must enter a content')])
attachment = FileField('Attachment')
But when I add this code :
from flask import session
uid = session.get('user_id')
It shows me this error:
raise RuntimeError('working outside of request context')
RuntimeError: working outside of request context
So how can I solve it?
You should use uid = session.get('user_id') only on request, for example:
app = Flask(__name__)
#app.route('/')
def home():
'''dispatcher functions works with request context'''
uid = session.get('user_id')
return str(uid)
If this code calling not from request (another process, another thread, celery, unit test and etc), then you should create request context manually or avoid use context stack variables:
with app.test_request_context():
uid = session.get('user_id')
Ok , I find how to solve that problem.
I think one of the best way is to use session in the route file.
This is my form code:
from flask_wtf import Form
from wtforms import SelectField
class Test(Form):
name = SelectField('Name')
So I have an app with "our" name, I have access to session in this app:
from flask import Blueprint,session,render_template
from form import Test
our = Blueprint('our',__name__)
#our.route('/')
def index():
form = Test()
#session['name'] = 'hedi'
if session.get('name').lower() == "morteza":
form.name.choices = ((1,'mori'),(2,'hedi'))
else:
form.name.choices = ((1,'you'))
return render_template('index.html',form=form)
#return str(session.get('name'))
Now I changed my form field data via app. form.name.choices=....

Categories

Resources