Flask migration fails - python-3.x

I'm making migrations in Flask using unsurprisingly Flask-Migrate.
once I execute python manage.py db init it creates directory migrations with initial migrations file. Then
I execute python manage.py db migrate and I get this:
...
...
target_metadata = current_app.extensions['migrate'].db.metadata
AttributeError: 'NoneType' object has no attribute 'metadata'
I understand from this output that 'migrate' is None hence I'm getting an attribute error.
models.py:
from sqlalchemy.sql import func
from project import db, bcrypt
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(128), nullable=False, unique=True)
email = db.Column(db.String(128), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False)
active = db.Column(db.Boolean(), default=True, nullable=False)
created_date = db.Column(db.DateTime, default=func.now(), nullable=False)
def __init__(self, username, email, password):
self.username = username
self.email = email
self.password = bcrypt.generate_password_hash(password).decode()
def to_json(self):
return {
'id': self.id,
'username': self.username,
'email': self.email,
'active': self.active,
}
The question is why nothing is being passed to it ? I'm following a tutorial and I'm not supposed to have this error.
I've got this from similar topic:
NoneType means that instead of an instance of whatever Class or Object
you think you're working with, you've actually got None. That usually
means that an assignment or function call up above failed or returned
an unexpected result.
this is what I've found in env.py file in the migrations directory:
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata
current_app is being imported from Flask but doesn't contain the extension migrate from which I need to use the metadata.
There's no reason for it to be throwing None though because the extension is correctly initilised in __init__.py file:
...
...
from flask_migrate import Migrate
db = SQLAlchemy()
toolbar = DebugToolbarExtension()
cors = CORS()
migrate = Migrate()
bcrypt = Bcrypt()
def create_app(script_info=None):
app = Flask(__name__)
app_settings = os.getenv('APP_SETTINGS')
app.config.from_object(app_settings)
app.config.from_object('project.config.DevelopmentConfig')
toolbar.init_app(app)
cors.init_app(app)
db.init_app(app)
migrate.init_app(app) # <--
bcrypt.init_app(app)
from project.api.users import users_blueprint
app.register_blueprint(users_blueprint)
#app.shell_context_processor
def ctx():
return {'app': app, 'db': db}
return app

I had a missing argument in the initialization of the migrate extension. Migrate takes in the app instance and the instance of db.
def create_app(script_info=None):
app = Flask(__name__)
app_settings = os.getenv('APP_SETTINGS')
app.config.from_object(app_settings)
app.config.from_object('project.config.DevelopmentConfig')
toolbar.init_app(app)
cors.init_app(app)
db.init_app(app)
migrate.init_app(app, db) # <--
bcrypt.init_app(app)
from project.api.users import users_blueprint
app.register_blueprint(users_blueprint)
#app.shell_context_processor
def ctx():
return {'app': app, 'db': db}
return app

Related

Connecting to ready Azure Database with Flask and SQLAlchemy, getting app context error

I have this code that is trying to connect to a user table in a database:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import yaml
db_info = yaml.safe_load(open('db.yaml'))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pyodbc://{dbuser}:{dbpass}#{server}.database.windows.net/{' \
'dbname}?driver=ODBC+Driver+17+for+SQL+Server'.format(
dbuser=db_info['user'],
dbpass=db_info['password'],
server=db_info['server'],
dbname=db_info['name']
)
db = SQLAlchemy(app)
class Users(db.Model):
ID = db.Column(db.Integer, primary_key=True, nullable=False)
UserName = db.Column(db.Text)
PhoneNum = db.Column(db.Text)
Password = db.Column(db.Text)
YearOfStudy = db.Column(db.Integer)
def __repr__(self):
return '<User %r>' % self.ID
#app.route('/')
def hello_world(): # put application's code here
print(Users.query.all())
return "Hello World"
if __name__ == '__main__':
app.run()
However when I run it, the link generated by the flask application doesn't load and the program terminates from timing out.
I did some debugging and saw that Users.query call results in an error as such:
Working outside of application context.
This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
I tried using with app.app_context to run the program by using code as such:
def __repr__(self):
return '<User %r>' % self.username
if __name__ == '__main__':
with app.app_context():
print(User.query.all())
But it didn't work. I also tried doing this:
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mssql+pyodbc://{dbuser}:{dbpass}#{server}.database.windows.net/{' \
'dbname}?driver=ODBC+Driver+17+for+SQL+Server'.format(
dbuser=db_info['user'],
dbpass=db_info['password'],
server=db_info['server'],
dbname=db_info['name']
)
db.init_app(app)
return app
app = create_app()
...
...
if __name__ == '__main__':
app.run()
Which had moderate success but the queries for User.query.all() still don't show, and filter_by() functions don't work either.
I also cannot use db.create_all() as this is a ready database, so I can't wipe the database I'm working on

UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:"

I have been trying to solve an issue related to SQLALCHEMY in Flask as my db is not getting created even though I set the SQLACHEMY_DATABASE_URI to "app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'".
In the warning it says the 'sqlite:///:memory:'. When db.create_all() is call test.sql file is not created and also in the UI I see errors as mentioned bellow:
Instance of 'SQLAlchemy' has no 'Column' memberpylint(no-member) and 3 others
Please help in resolving this issue and generating the db and SQL file.
from flask import Flask, render_template, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
#Initializing database
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
#Creating model
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(200), nullable=False)
completed = db.Column(db.Integer, default=0)
date_created = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return '<Task %r>' % self.id
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)

raise exc.NoSuchModuleError( sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgresql

I created a sample flask application, I want to connect PostgreSQL database to my project.
I installed flask_sqlalchemy.
here is my Code
from flask import Flask, url_for, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://michealscott:dwight#localhost:5432/michealscott'
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'books'
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
#app.route('/')
def hello_world():
return render_template("index.html")
I cd-ed into my src directory and executed:
python
>> from app import db
>> db.create_all()
then the above error shows up.
After searching over internet. I also did
pip install psycopg2
still no luck.
there is a same question on stack overflow and couple of answers/suggestions. I was not able to comment on the post so asking it again pardon me!
Please help.
Thank you in advance.

Flask-SQLAlchemy invalid identifier on ID column

I am trying to use the Python Terminal to add a user using the following commands:
from app import db
from app.models import User, Post
u = User(username='Jordan',email='jtest#test.net')
db.session.add(u)
db.session.commit()
Below is my model:
class User(db.Model):
id = db.Column(db.Integer, db.Sequence('id_seq'), primary_key=True)
username = db.Column(db.String(64), unique=True)
email = db.Column(db.String(120), unique=True)
password = db.Column(db.String(128))
posts = db.relationship('Post', backref='author',lazy='dynamic')
def __repr__(self):
return 'User {}'.format(self.username)
Init script:
from flask import Flask
from config import Config, SnowflakeImpl
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
# Creates an instance of the flask application
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from app import routes, models
sqlalchemy.exc.StatementError: (sqlalchemy.exc.ProgrammingError) (snowflake.connector.errors.ProgrammingError) 000904 (42000): SQL compilation error: error line 1 at position 7
invalid identifier 'ID_SEQ.NEXTVAL' [SQL: 'INSERT INTO user (id, username, email, password) VALUES (%(id)s, %(username)s, %(email)s, %(password_hash)s)'] [parameters: [{'email': 'jtest#test.net', 'username': 'Jordan', 'password': None}]] (Background on this error at: http://sqlalche.me/e/f405)
This is the error I am receiving, from what I've read online this should work but it's feeding back an 'invalid identifier' error.
Found the solution, since I am using the flask migrate package I went into the versions folder and observed in the migrate script for my User table my 'Sequence' function was not being included. It was causing my ID to have an Invalid Identifier error.
def upgrade():
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=64), nullable=True),
sa.Column('email', sa.String(length=120), nullable=True),
sa.Column('password_hash', sa.String(length=128), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email'),
sa.UniqueConstraint('username')
)

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table

I defined table name users_table and run db.create_all() to create the table, but get error "no such table user_table" on commit for updating user info.
How I test :
(under /project) python3 manage.py shell
>>> u = User(email='foo#bar.com', username='foobar', password='player')
>>> db.create_all()
>>> db.session.add(u)
>>> db.session.commit() # with following error message
Traceback (most recent call last):
File "C:\...\Python\Python36-32\lib\site-packages\sqlalchemy\engine\base.py", line 1182, in _execute_context
context)
File "C:\...\Python\Python36-32\lib\site-packages\sqlalchemy\engine\default.py", line 470, in do_execute
cursor.execute(statement, parameters)
sqlite3.OperationalError: no such table: users_table
...
...
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: users_table
/project/app/_init_.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
return app
/project/app/models.py:
import os
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash
from flask import Flask
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users_table'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<User %r>' % self.username
#property
def password(self):
raise AttributeError('Password is not a readable attribute')
#password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
project/config.py:
import os
basedir = os.path.abspath(os.path.dirname(\__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'fhuaioe7832of67^&*T#oy93'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
#staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
config = {
'development': DevelopmentConfig,
'default': DevelopmentConfig,
}
project/manage.py:
import os
from app import create_app, db
from app.models import User
from flask_script import Manager, Shell
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
def make_shell_context():
return dict(app=app, db=db, User=User)
manager.add_command("shell", Shell(make_context=make_shell_context))
if __name__ == '__main__':
manager.run()
I just got done setting up a Flask app and I dealt with this kind of problem.
I strongly suspect the problem here is that the instance of db that you are creating in __init__.py is unaware of the contents of models.py, including the User class. The db object in __init__.py is a totally separate object from the db you are creating in models.py. So when you run db.create_all() in __init__.py, it is checking the list of tables that it knows about and isn't finding any. I ran into this exact issue.
What I discovered is that the models (like User) are registered with the particular db object that is listed in the model's class definition (e.g. class User(db.Model):).
So basically my understanding is that the way to fix this is to run db.create_all() using the same instance of db that is being used to define the models. In other words, run db.create_all() from within models.py.
Here's my code so you can see how I have it set up:
app.py:
#!flask/bin/python
import os
from flask import Flask
class CustomFlask(Flask):
jinja_options = Flask.jinja_options.copy()
jinja_options.update(dict(
variable_start_string='%%', # Default is '{{', I'm changing this because Vue.js uses '{{' / '}}'
variable_end_string='%%',
))
app = CustomFlask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
import yaml
if os.environ['SERVER_ENVIRONMENT'] == 'PRODUCTION':
config_filename = "production.yaml"
elif os.environ['SERVER_ENVIRONMENT'] == 'LOCAL':
config_filename = "local.yaml"
else:
config_filename = "local.yaml"
base_directory = path = os.path.dirname(os.path.realpath(__file__))
with open(base_directory + "/config/" + config_filename) as config_file:
config = yaml.load(config_file)
db_config = config['database']
SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}#{hostname}/{databasename}".format(
username=db_config['username'],
password=db_config['password'],
hostname=db_config['hostname'],
databasename=db_config['databasename'],
)
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_POOL_RECYCLE"] = 299
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
db.app = app
def clear_the_template_cache():
app.jinja_env.cache = {}
app.before_request(clear_the_template_cache)
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
#login_manager.user_loader
def load_user(email):
from models import User
return User.query.filter_by(email=email).first()
if __name__ == '__main__':
from routes import web_routes
app.register_blueprint(web_routes)
from api import api
app.register_blueprint(api)
# To get PyCharm's debugger to work, you need to have "debug=False, threaded=True"
#app.run(debug=False, threaded=True)
app.run(debug=True)
models.py:
from app import db
import datetime
from werkzeug.security import generate_password_hash, \
check_password_hash
class Song(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(80))
datetime_created = db.Column(db.DateTime, default=datetime.datetime.utcnow())
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
lines = db.relationship('Line', cascade="all,delete", backref=db.backref('song', lazy='joined'), lazy='dynamic')
is_deleted = db.Column(db.Boolean, default=False)
class Line(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
song_id = db.Column(db.Integer, db.ForeignKey('song.id'))
spans_of_time = db.relationship('SpanOfTime', cascade="all,delete", backref=db.backref('line', lazy='joined'), lazy='dynamic')
class SpanOfTime(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
line_id = db.Column(db.Integer, db.ForeignKey('line.id'))
starting_64th = db.Column(db.Integer) # I'm assuming the highest-granularity desired will be a 1/64th note-length.
length = db.Column(db.Integer) # I guess this'll be in 1/64th notes, so a 1/16th note will be '4'.
content = db.Column(db.String(80))
class User(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(80), primary_key=True, unique=True)
display_name = db.Column(db.String(80), default="A Rhymecraft User")
password_hash = db.Column(db.String(200))
datetime_subscription_valid_until = db.Column(db.DateTime, default=datetime.datetime.utcnow() - datetime.timedelta(days=1))
datetime_joined = db.Column(db.DateTime, default=datetime.datetime.utcnow())
songs = db.relationship('Song', cascade="all,delete", backref=db.backref('user', lazy='joined'), lazy='dynamic')
def __init__(self, email, password):
self.email = email
self.set_password(password)
def __repr__(self):
return '<User %r>' % self.email
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return str(self.email)
def init_db():
db.create_all()
# Create a test user
new_user = User('a#a.com', 'aaaaaaaa')
new_user.display_name = 'Nathan'
db.session.add(new_user)
db.session.commit()
new_user.datetime_subscription_valid_until = datetime.datetime(2019, 1, 1)
db.session.commit()
if __name__ == '__main__':
init_db()
Very simple solution: in the app.py or main.py you can just add these lines of code for fixing this issue:
#app.before_first_request
def create_tables():
db.create_all()
In your case, require to add following code into __init__.py:
from models import User, Role
#app.shell_context_processor
def make_shell_context():
return dict(db=db, User=User, Role=Role)
then you do your previous works, it's all work.
I run into the same problem, after doing a YT tutorial. I solved it by adding this code at the end of my __init__.py
from .models import User, Post
with app.app_context():
db.create_all()
Sidenote: Most tutorials don't use the with app.app_context(): . I think there was a update in flask, which is why this is needed. This caused errors in my code and maybe it helps someone who reads this.
I would like to mention that it was the flask tutorial from "corey schafer" after "part 6 - user authentication", and the error appeared when i ran some tests. just in case anyone else is doing the exact same tutorial and therfore finds it easier to identify my answer as helpful. I am not mentioning the creater for advertisement. I hope this is ok.
Create a folder named "instance" in the root directory and move your database file to that folder.

Resources