i'm beginner with flask-sqlalchemy.
i encountered a problem maybe caused by using backref.
the api(view api. it renders template) is like this.
#board.route('/')
def index():
page = request.args.get('page', 1, type=int)
q = Article.query.order_by(Article.create_date.desc())
article_list_pagination = q.paginate(page, per_page=10)
return render_template('board.html', article_list=article_list_pagination)
and the model is like this
class Answer(db.Model):
__tablename__ = 'answer'
id = db.Column(db.Integer, primary_key=True)
article_id = db.Column(db.Integer, db.ForeignKey('article.id', ondelete='CASCADE'))
article = db.relationship('Article', backref=db.backref('answer_set'))
user_id = db.Column(db.String(255), nullable=False)
name = db.Column(db.String(255), nullable=False)
content = db.Column(db.Text(), nullable=False)
create_date = db.Column(db.DateTime(), nullable=False)
update_date = db.Column(db.DateTime(), nullable=True)
when i request the api every 20 times, i get this error
sqlalchemy.exc.TimeoutError: QueuePool limit of size 10 overflow 10 reached, connection timed out, timeout 30.00 (Background on this error at: https://sqlalche.me/e/14/3o7r)
here is what i tried to solve the error.
give lazy options to db.relationship. but doesn't work
db.session.close(). but it makes another error
sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <Article at 0x1772756baf0> is not bound to a Session; lazy load operation of attribute 'answer_set' cannot proceed
debug=False. it doesn't work, too.
how can i get over this problem?
+++
when I remove
article = db.relationship('Article', backref=db.backref('answer_set')) from the model and
add db.session.close() before return template,
it doesn't make error, but i need it.
what should i do?
+++++ answers for comment #branco
i'm just using flask-sqlalchemy paginate method.
https://flask-sqlalchemy.palletsprojects.com/en/2.x/api/
and i'm running this app at app.py
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import JWTManager
import config
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.secret_key = 'secret_key_for_flash'
app.config.from_object(config)
db.init_app(app)
migrate.init_app(app, db)
from models.user import User
from models.article import Article
from models.answer import Answer
from blueprints.main import main
from blueprints.login import login
from blueprints.register import register
from blueprints.board.board import board
from blueprints.board.article import article
from blueprints.board.answer import answer
app.register_blueprint(main)
app.register_blueprint(login)
app.register_blueprint(register)
app.register_blueprint(board)
app.register_blueprint(article)
app.register_blueprint(answer)
app.config['JWT_SECRET_KEY'] = 'jwt_secret_key'
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = config.expires_access
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = config.expires_refresh
app.config['JWT_TOKEN_LOCATION'] = ['cookies']
JWTManager(app)
return app
if __name__ == '__main__' :
create_app().run(debug=True)
finally, i solved this problem. i just gave lazy options to db.relationship. but didn't work. i had to give lazy option to db.backref. like
article = db.relationship('Article', backref=db.backref('answer_set', lazy='joined'))
and added
db.session.close()
after i called paginate method
Related
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.
This is what I have in my app.py:
from flask import Flask, render_template, url_for, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///D:/Documents/.my projects/flask-website/blog.db'
db = SQLAlchemy(app)
class Blogpost(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50))
subtitle = db.Column(db.String(50))
author = db.Column(db.String(20))
date_posted = db.Column(db.DateTime)
content = db.Column(db.Text)
if __name__ == '__main__':
app.run(debug=True)
and in python terminal, I try this:
>>> from app import db
>>> db.create_all()
Then I check to see if the table has been created using command prompt:
> sqlite3 blog.db
> .tables
Nothing gets returned, which I believe means that no tables are in the database. I'm following the tutorial here, but maybe the tutorial is out of date, so I'm not really sure where to go from here.
I am using python 3.9
Turns out I had my file path wrong in app.config['SQLALCHEMY_DATABASE_URI']... currently hitting my head on my desk because I have spent more time than I care to admit on this issue.
URI:
SQLALCHEMY_DATABASE_URI = "mssql+pymssql://user:password123#127.0.0.1/DbOne"
SQLALCHEMY_BINDS = {
"sql_server": "mysql+pymysql://user:password123#127.0.0.1/DbTwo"
}
Models.py
class CrimMappings(db.Model):
__tablename__ = "crim_mappings"
id = db.Column(db.Integer, primary_key=True)
date_mapped = db.Column(db.Date)
county_id = db.Column(db.Integer)
state = db.Column(db.String(20))
county = db.Column(db.String(100))
AgentID = db.Column(db.String(100), unique=True)
CollectionID = db.Column(db.String(100))
ViewID = db.Column(db.String(100))
class LicenseType(db.Model):
__bind_key__ = "sql_server"
__table__ = db.Model.metadata.tables["sbm_agents"]
however it throws me a KeyError saying the 'sbm_agents' table is not found which it should be there because I've specified the bind key to point to the sql_server bind.
__init__.py
from os.path import join,dirname,abspath
from flask_admin import Admin
from project.apps.flask_apps.user_app.forms import UserAdminForm
from flask_admin.contrib.sqla import ModelView
from project import app_factory, db
from project.apps.flask_apps.admin_own.views import AdminHome, Utilities
from project.apps.flask_apps.admin_own.models import CredentCheckMappings, AllAgents, LicenseTypes
from project.apps.flask_apps.admin_own.forms import MasterAgentForm, AgentMappingsModelView, AllLicenseForm
from project.apps.flask_apps.user_app.models import Users
def create_application():
config_path = join(dirname(abspath(__file__)), "config", "project_config.py")
app = app_factory(config_path=config_path)
admin = Admin(app, template_mode="bootstrap3", base_template="base_templates/admin_base.html",
index_view=AdminHome())
with app.app_context():
db.create_all()
db.Model.metadata.reflect(db.engine)
admin.add_view(MasterAgentForm(AllAgents, db.session))
admin.add_view(UserAdminForm(Users, db.session))
admin.add_view(Utilities(name="Utilities", endpoint="utilities"))
admin.add_view(AgentMappingsModelView(CredentCheckMappings, db.session))
admin.add_view(AllLicenseForm(LicenseTypes, db.session))
return app
application = create_application()
if __name__ == "__main__":
application.run(host="0.0.0.0", port=5000, debug=True)
what am I missing here?
I've tried this:
flask sqlalchemy example around existing database
but im getting the KeyError
did something change or im missing a step?
Edit:
For people wanting to know how I got around this.
I went straight to SqlAlchemy and did this
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.automap import automap_base
from urllib.parse import quote_plus
engine = create_engine("mssql+pyodbc:///?odbc_connect="+ quote_plus("DRIVER={FreeTDS};SERVER=172.1.1.1;PORT=1433;DATABASE=YourDB;UID=user;PWD=Password"))
metadata = MetaData(engine)
Session = scoped_session(sessionmaker(bind=engine))
LicenseType= Table("sbm_agents", metadata, autoload=True)
that way im not reflecting the entire database and only choose to reflect certain tables. because it turns out that reflecting the entire database is slow.
although this approach is a little tougher because you have to configure FREETDS but its doable just a little tedious and confusing at first
Use db.reflect() instead of db.Model.metadata.reflect(db.engine).
So this is my code below. I'm trying to create a database, with one story table. The input comes from the html input part
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask import request, redirect, url_for
app = Flask(__name__)
password = input("Your database password: ")
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://adambodnar:{}#localhost/user_stories'.format(password)
db = SQLAlchemy(app)
class Story(db.Model):
id = db.Column(db.Integer, primary_key=True)
story_title = db.Column(db.String(80), unique=True)
user_story = db.Column(db.Text)
acceptance_criteria = db.Column(db.Text)
business_value = db.Column(db.Integer)
estimation = db.Column(db.Integer)
status = db.Column(db.String(30))
def __init__(self, story_title, user_story, acceptance_criteria, business_value, estimation, status):
self.story_title = story_title
self.user_story = user_story
self.acceptance_criteria = acceptance_criteria
self.business_value = business_value
self.estimation = estimation
self.status = status
#app.route('/')
def index():
return render_template('form.html')
#app.route('/story', methods=['POST'])
def story_post():
new_story = Story(request.form['story_title'],request.form['user_story'], request.form['acceptance_criteria'], request.form['business_value'], request.form['estimation'], request.form['status'])
db.session.add(new_story)
db.session.commit()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
when I try to run this, I get the following error:
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) relation "story" does not exist
LINE 1: INSERT INTO story (story_title, user_story, acceptance_crite...
^
[SQL: 'INSERT INTO story (story_title, user_story, acceptance_criteria, business_value, estimation, status) VALUES (%(story_title)s, %(user_story)s, %(acceptance_criteria)s, %(business_value)s, %(estimation)s, %(status)s) RETURNING story.id'] [parameters: {'acceptance_criteria': 'asdasd', 'estimation': '1', 'user_story': 'asd', 'status': 'Planning', 'story_title': 'asd', 'business_value': '100'}]
The story table is not even created, I checked it through pgAdmin. I've tried a lot of things, some questions suggested to drop the table, but it's not created
Have you followed the quickstart guide for Flask and sqlalchemy? Anyway, on the guide you will notice that it says to do this:
To create the initial database, just import the db object from an
interactive Python shell and run the SQLAlchemy.create_all() method to
create the tables and database:
>>> from yourapplication import db
>>> db.create_all()
In the code you included with your question the table creation code seems to be missing, which explains the table not being created.
You can consider including db.create_all() with your application (put it right after db = SqlAlchemy(app)) - if this wrapper functions like the standard sqlalchemy version it should only create new tables and not blow up if tables already exist.
I'm trying to integrate PostgreSQL and SQLAlchemy but SQLAlchemy.create_all() is not creating any tables from my models.
My code:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass#localhost/flask_app'
db = SQLAlchemy(app)
db.create_all()
db.session.commit()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
admin = User('admin', 'admin#example.com')
guest = User('guest', 'guest#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
users = User.query.all()
print users
But I get this error: sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "user" does not exist
How can I fix this?
You should put your model class before create_all() call, like this:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass#localhost/flask_app'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
with app.app_context():
db.create_all()
db.session.add(User('admin', 'admin#example.com'))
db.session.add(User('guest', 'guest#example.com'))
db.session.commit()
users = User.query.all()
print(users)
If your models are declared in a separate module, import them before calling create_all().
Say, the User model is in a file called models.py,
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://login:pass#localhost/flask_app'
db = SQLAlchemy(app)
# See important note below
from models import User
with app.app_context():
db.create_all()
db.session.add(User('admin', 'admin#example.com'))
db.session.add(User('guest', 'guest#example.com'))
db.session.commit()
users = User.query.all()
print(users)
Important note: It is important that you import your models after initializing the db object since, in your models.py you also need to import the db object from this module.
If someone is having issues with creating tables by using files dedicated to each model, be aware of running the "create_all" function from a file different from the one where that function is declared.
So, if the filesystem is like this:
Root
--app.py <-- file from which app will be run
--models
----user.py <-- file with "User" model
----order.py <-- file with "Order" model
----database.py <-- file with database and "create_all" function declaration
Be careful about calling the "create_all" function from app.py.
This concept is explained better by the answer to this thread posted by #SuperShoot
This is probably not the main reason why the create_all() method call doesn't work for people, but for me, the cobbled together instructions from various tutorials have it such that I was creating my db in a request context, meaning I have something like:
# lib/db.py
from flask import g, current_app
from flask_sqlalchemy import SQLAlchemy
def get_db():
if 'db' not in g:
g.db = SQLAlchemy(current_app)
return g.db
I also have a separate cli command that also does the create_all:
# tasks/db.py
from lib.db import get_db
#current_app.cli.command('init-db')
def init_db():
db = get_db()
db.create_all()
I also am using a application factory.
When the cli command is run, a new app context is used, which means a new db is used. Furthermore, in this world, an import model in the init_db method does not do anything, because it may be that your model file was already loaded(and associated with a separate db).
The fix that I came around to was to make sure that the db was a single global reference:
# lib/db.py
from flask import g, current_app
from flask_sqlalchemy import SQLAlchemy
db = None
def get_db():
global db
if not db:
db = SQLAlchemy(current_app)
return db
I have not dug deep enough into flask, sqlalchemy, or flask-sqlalchemy to understand if this means that requests to the db from multiple threads are safe, but if you're reading this you're likely stuck in the baby stages of understanding these concepts too.