Why SQLAlchemy won't commit changes? - python

I've done this so many times before successfully but all of the sudden I can't seem
to make it work. I'm creating tables in my MySQL database using Flask SQLAlchemy as a middleman.
Also using pymysql adapter.
Can you please check my "plumbing" is correct ?
my init.py :
import werkzeug
werkzeug.cached_property = werkzeug.utils.cached_property
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from .config import DevConfig
db = SQLAlchemy()
bcrypt = Bcrypt()
def create_app(script_info=None):
app = Flask(__name__)
app.config.from_object(DevConfig)
bcrypt.init_app(app)
db.init_app(app)
from .flask_app import users_blueprint
app.register_blueprint(users_blueprint)
#app.shell_context_processor
def ctx():
return {'app': app, 'db': db}
return app
models.py:
from project import db, bcrypt
class User(db.Model):
__tablename__ = 'users'
...
...
config.py:
import os
class BaseConfig:
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://mark:supersecret#localhost/database1?charset=utf8mb4' # the "?charset" thingy is there to avoid encoding warnings from SQLAlchemy
SECRET_KEY = 'pythonrocks'
class DevConfig(BaseConfig):
DEBUG = True
class ProdConfig(BaseConfig):
DEBUG = False
interpreter:
Instance: /home/mark/project/instance
In [1]: db
Out[1]: <SQLAlchemy engine=mysql+pymysql://mark:***#localhost/database1?charset=utf8mb4>
In [2]: db.create_all()
In [3]: db.session.commit()
I get no error output. The tables are just not being created on commit.
mysql> show tables;
Empty set (0.00 sec)
How can I check what's causing this ? The dev server is running.

You're not importing your models before calling db.create_all() - SQLAlchemy simply doesn't know about your models - and thus can't create the tables.
Import it first, then call db.create_all() and db.session.commit().

Related

Flask DB migrate to support multiple databases using binds

I am using Flask Application with flask-migrate. I have initialized the app with single database but now the requirement is to add multiple databases.
Here are the steps that I followed with the below code :-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
from flask_migrate import Migrate
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'database1.db')
"""
app.config['SQLALCHEMY_BINDS'] = {
'database2' : 'sqlite:///' + os.path.join(basedir, 'database2.db')
}
"""
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class Table1(db.Model):
id = db.Column(db.Integer, primary_key=True)
"""
class Table2(db.Model):
__bind_key__ = 'database2'
id = db.Column(db.Integer, primary_key=True)
"""
#app.route('/add1')
def index():
item = Table1(id=2)
db.session.add(item)
db.session.commit()
return 'Added value'
"""
#app.route('/add2')
def index2():
item = Table2(id=2)
db.session.add(item)
db.session.commit()
return 'Added table2 value'
"""
if __name__ == '__main__':
app.run(debug=True)
Initialized the code as below
flask db init
flask db migrate
flask db upgrade
Visit http://127.0.0.1:5000/add1 to add to database1
Now uncomment the code so that the database2 can be added. On running flask db init again with --multidb switch, an error is reported.
(venv) bash-4.1$ flask db init --multidb
Error: Directory migrations already exists and is not empty
How can I convert an existing flask project with migrations to support multiple databases? Also, these multiple databases will evolve over the time i.e. I might have to add more databases. So, what is the best way to keep on adding more databases?
EDIT
One solution, I find is to remove the alembic_version table from existing database, remove the migrations folder and then do db init --multidb. I am okay resetting the migrations but want to know if this is the only solution?

Flask-SQLAlchemy doesn't create table

I am trying to use PostgreSQL with Flask-SQLAlchemy. I made a database named data_collector using pgAdmin4. When I try to create a table it's not getting created. I think the connection to the database is not getting established.
I am trying to run it from cmd as:
from app import db
db.create_all()
from flask import Flask, render_template,request
from flask_sqlalchemy import SQLAlchemy
app=Flask(__name__)
app.config['SQLALCHEMY DATABASE_URI'] = 'postgresql://postgres:postgresql#localhost/data_collector'
db=SQLAlchemy(app)
class Data(db.Model):
__tablename__="data"
id=db.Column(db.Integer,primary_key=True)
email_=db.Column(db.String(120),unique=True)
height_=db.Column(db.Integer)
def __init__(self,email_,height_):
self.email_=email_
self.height_=height_
db.create_all()
You didn't commit to the database after creating the tables.
You can do that by:
with app.app_context():
db.create_all()
db.session.commit()
Do something like this.
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
db = SQLAlchemy(app)
# ---snip---
with app.app_context():
db.create_all()
db.session.commit() # <- Here commit changes to database
#app.route("/")
def index():
return "Hello, World!"
This should solve your problem.
If you want to reset(delete) your database then:
with app.app_context():
db.drop_all()
db.session.commit()
Nothing is written or deleted or updated in database unless you commit using
db.session.commit()
If you want to revert the changes before comitting use:
db.session.rollback()
Finally got the solution after alot of Googling.
You must import all the models before calling db.create_all() function like this,
def create_db():
from src import models
db.create_all()
db.session.commit()
I have all my models in single file but if you have different files, make sure to import them all.

Creating a database in flask sqlalchemy

I'm building a Flask app with Flask-SQLAlchemy and I'm trying to write a script that will create a Sqlite3 database without running the main application. In order to avoid circular references, I've initialized the main Flask app object and the SQLAlchemy database object in separate modules. I then import and combine them in a third file when running the app. This works fine when I'm running the app, as the database is built and operates properly when create rows and query them. However, when I try to import them in another module, I get the following error:
RuntimeError: application not registered on db instance and no applicationbound to current context
My code looks like the following:
root/create_database.py
from application.database import db
from application.server import app
db.init_app(app)
db.create_all()
root/run.sh
export FLASK_APP=application/server.py
flask run
root/application/init.py
from database import db
from server import app
db.init_app(app)
from routes import apply_routes
apply_routes(app)
root/application/database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
root/application/server.py
from flask import Flask
import os
app = Flask(__name__)
path = os.path.dirname( os.path.realpath(__file__) )
database_path = os.path.join(path, '../mydb.sqlite')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + database_path
root/application/models/init.py
from user import User
root/application/models/user.py
from application.database import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
password = db.Column(db.String(120))
def __init__(self, username, password):
self.username = username
self.password = password
In my create_database.py script I'm trying to make sure that the SQLAlchemy db instance is configured with the config details from the app object, but it doesn't seem to be connecting for some reason. Am I missing something important here?
You either have to create a request or you have to create the models with sqlalchemy directly. We do something similar at work and chose the former.
Flask lets you create a test request to initialize an app. Try something like
from application.database import db
from application.server import app
with app.test_request_context():
db.init_app(app)
db.create_all()

Can I avoid circular imports in Flask and SQLAlchemy

app/init.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__ name __)
db = SQLAlchemy(app)
from app import views, models
app/models.py:
from app import db # I want to avoid this everywhere
I really don't like my submodules having a dependency on their parent. Also can the global package variables be avoided too? I want a more OO solution.
One alternative for app is to use Blueprints I think, but then I loose the route decorator. Also the same cannot be done for db with SQLAlchemy (or can it?).
Take a look at this project: https://github.com/sloria/cookiecutter-flask
It's a great example for doing things the right way. Many of great Flask features are used: blueprints, application factories and more.
Here is how they register extensions, such as SQLAlchemy Database:
# app/extensions.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
...
# app/app.py
from app.extensions import db
def create_app(config_object=ProdConfig):
app = Flask(__name__.split('.')[0])
app.config.from_object(config_object)
register_extensions(app)
...
def register_extensions(app):
db.init_app(app)
...
Try use 3rd. We create exts.py file to instancing SQLAlchemy like this:
exts.py
from flask_sqlalchemy import SQLAlchemy
from flask_xxx import xxx
db = SQLAlchemy()
...
run.py
from flask import Flask
from .exts import db, ...
def register_extensions(app):
db.init_app(app)
...
def create_app(config):
app = Flask(__ name __)
app.config.from_object(config)
register_extensions(app)
return app
app = create_app(config)
models.py
from .exts import db
class XXXModel(db.Model):
pass

Use Alembic to upgrade in-memory sqlite3 database

I have a Flask app created with an app factory. When testing with pytest, I want to use an in-memory sqlite database because it is much faster than using temporary files. I'm using Flask-Migrate to integrate Alembic and Flask-SQLAlchemy. Flask-Migrate uses command line commands to manage the database. How can I run migrations to set up the database from within my test code?
config.py:
class DefaultConfig(object):
DEBUG = True
TESTING = True
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-change'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
__init__.py:
db = SQLAlchemy()
socketio = SocketIO()
migrate = Migrate()
def create_app(config=None):
app = Flask(__name__)
if config is not None:
config_path = os.path.abspath(config)
app.config.from_pyfile(config_path)
elif os.path.isfile(os.path.abspath(CONFIGFILE)):
app.config.from_pyfile(os.path.abspath(CONFIGFILE))
else:
app.config.from_object(DefaultConfig)
db.init_app(app)
socketio.init_app(app)
migrate.init_app(app, db)
return app
fixtures.py:
from flask.ext.migrate import upgrade
from . import create_app, db
from .models import User
class AppFixture(object):
def __init__(self):
self.app = create_app()
self.db = db
with self.app.app_context():
upgrade()
self.users = User.query.all()
Calling upgrade() above doesn't work, I get OperationalError: (sqlite3.OperationalError) no such table: user [SQL: u'SELECT... at the Users.query line afterwards.

Categories