Flask migration is not applying on all tables - python

i have a project where i create four tables (users,products, agents, customer) when i do migration with:
flask db init,
flask db migrate,
flask db upgrade,
only users and products get migrated
here it is the structure of my project:
my code for user model is:
from main.extensions import db
from main.shared.base_model import BaseModel, HasCreatedAt,
HasUpdatedAt
class User(BaseModel, HasCreatedAt, HasUpdatedAt):
tablename = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
phone = db.Column(db.Integer)
my code for every module starting by agent model:
from main.extensions import db
class Agent(db.Model):
__tablename__ = 'agents'
id = db.Column(db.Integer, primary_key=True)
picture = db.Column(db.String)
def __init__(self,email, password, phone, picture):
self.email = email
self.password=password
self.phone=phone
self.picture=picture
and for the model in customer is:
from main.modules.user.models import User
from main.extensions import db
class Customer(User):
__tablename__ = 'customers'
approved = db.Column(db.Boolean)
picture = db.Column(db.String)
def __init__(self, email, password, phone, picture, approved):
self.approved = approved
self.picture = picture
User.__init__(self,email,password,phone)
and finnaly the products model has:
from main.extensions import db
from main.shared.base_model import BaseModel, HasCreatedAt, HasUpdatedAt
class Product(BaseModel, HasCreatedAt, HasUpdatedAt):
__tablename__ = 'products'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
the settings.py contains the following code:
and this init files for every model contains this code:
for the user __init.py:
from main.modules.users.api import blueprint as api
for the customer __init.py:
from main.modules.customer.api import blueprint as api
for the agent__init.py:
from main.modules.agent.api import blueprint as api
for the prodcut__init.py:
from main.modules.product.api import blueprint as api
import os
class DevSettings(Settings):
DEBUG = True
basedir = os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_DATABASE_URI="sqlite:///" + os.path.join(basedir, "data.sqlite")
SQLALCHEMY_TRACK_MODIFICATIONS=False
and the extension.py contains:
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
migrate = Migrate()
and the app.py contains this:
from flask import Flask, Blueprint
from main.extensions import db, migrate
from main.modules import product, agent, customer, user
from main.settings import DevSettings
MODULES = [ agent, customer,product, user]
main = Blueprint('main', __name__)
def create_app(settings=DevSettings):
app = Flask(__name__)
# Utiliser la configuration (settings).
app.config.from_object(settings)
app.config['SECRET_KEY'] = 'mysecretkey'
# On initialise les libraries Python.
# Init SQLAlchemy.
db.init_app(app)
# Init Migrate.
migrate.init_app(app, db)
app.register_blueprint(main)
register_modules(app)
return app
def register_modules(app):
for m in MODULES:
if hasattr(m, 'api'):
app.register_blueprint(m.api)

Related

No application found on Flask function

I have two file one for the DB model and the other is the main file. The creat_admin_user function does not work. When I try to run init.py I get "No application found. Either work inside a view function or push an application context". I have looked at the SQLAlchemy site and I have the db.init_app line and returning the app object. Not sure what else I am missing. The error appears to be on the user query which is the first line of the create_admin_user function.
--------------- __init__.py ---------------
from .models import User, Note, db, DB_NAME
from flask import Flask
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
create_database(app)
# create Admin user
create_admin_user()
return app
def create_database(app):
if not path.exists('website/' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
def create_admin_user():
user = User.query.filter_by(username='admin').first()
print("after query")
if user:
print("User already exists")
else:
# Add user to DB
add_user = User(first_name='LocalAdmin', username='admin', password=generate_password_hash(gen_password,
method='sha256'))
# adds user and commits the db.session.add(add_user)
db.session.commit()
print(f"Admin user created successfully")
--------------- Models.py ---------------
import datetime
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
db = SQLAlchemy()
DB_NAME = "database.db"
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(100))
last_name = db.Column(db.String(100))
email = db.Column(db.String(100))
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100))
domain = db.Column(db.String(100), nullable=False)
creation_date = db.Column(db.DateTime, default=datetime.datetime.now())
last_login = db.Column(db.DateTime, onupdate=datetime.datetime.now())
failed_login = db.Column(db.Integer)
active = db.Column(db.Integer, default=1)
Got it working. I added app.app_context().push() right before calling the create_admin function and it is working correctly now.
If you want to run functions which alters the Database of an Flask Application without starting the Flask Application you have to push the Application Context first.
So you have to call something like this:
self.app = create_app()
self.app_context = self.app.app_context()
self.app_context.push()
And don't forget to remove the context afterwords.
self.app_context.pop()

How to retrieve a row from SQLalchemy with flask

I am learning how to use SQLalchemy and databases in general with flask. I am following a tutorial and it uses the below classes and files.
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database
To show an inserted row in the database, the tutorial uses the following:
from app.models import User
>>> u = User(username='susan', email='susan#example.com')
>>> u
<User susan>
My problem is that I can not display the same output. I mean when I code the the statement, I get an error
from app.models import User
ImportError: No module named app.models
Please let me know how to adapt the posted code so I can retrieve data from database
Folder Structure:
d:\xxx\xxx\db1\app\models
d:\xxx\xxx\db1\__init__
d:\xxx\xxx\db1\config
** init **:
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from app import routes, models
config:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
# ...
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
models:
from app import db
from app.models import User
class User(db.Model):
id = db.Column(db.Integer, primaty_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<User {}>'.format(self.username)
You cannot import User on the same module where models is declared, so I don't think If you need that second line in models.py, Try commenting and see what happens
from app import db
from app.models import User ## I think the problems is
class User(db.Model):
id = db.Column(db.Integer, primaty_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<User {}>'.format(self.username)

MYSQLAlchemy/Flask doesn't recognise migrations

I am new to Flask/MYSQLAlchemy/Postgres and am still trying to understand it all.
I have got an app:
from flask import Flask
from flask_cors import CORS
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
def create_app(*args, app_name="SMARRTBROKER_API"):
# add sentry integration
sentry_sdk.init(
dsn="https://cd31f9dbcd56420fa0ca08422a441747#sentry.io/1369455",
integrations=[FlaskIntegration()]
)
app = Flask(app_name)
CORS(app, resources=r'/api/*')
# CORS(app, resources={r"/api/*": {"origins": "*"}}, supports_credentials=True)
app.config.from_object('api.config.DevelopmentConfig')
from api.api import api
app.register_blueprint(api, url_prefix='/api')
# app.config['SQLALCHEMY_ECHO'] = True
from api.models import db
db.init_app(app)
return app
And a manage.py file:
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from api.application import create_app
from api.models import db, Lead, User, Setting, Category, Keyword, keyword_identifier, Product, Plan
from filter_class import Filter
from filter_keyword import FilterKeyword
from sqlalchemy.dialects.postgresql import array
from sqlalchemy import or_, not_
from sqlalchemy import any_
from datetime import datetime, timedelta
from sqlalchemy.orm.attributes import flag_modified
from classification import Classification
app = create_app()
migrate = Migrate(app, db)
manager = Manager(app)
# provide a migration utility command
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
And a model.py file:
"""
models.py
Data classes for the api application
"""
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy.dialects.postgresql import ARRAY
import enum
import locale
db = SQLAlchemy()
...
class Setting(db.Model):
__tablename__ = 'settings'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow)
import_settings = db.Column(db.JSON, nullable=True)
def to_dict(self):
return dict(
id=self.id,
name=self.name,
created_at=self.created_at,
label=self.label
)
class Keyword(db.Model):
__tablename__ = 'keywords'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
label = db.Column(db.Text, nullable=False, unique=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow)
leads = db.relationship('Lead', secondary=keyword_identifier)
def to_dict(self):
return dict(
id=self.id,
label=self.label,
name=self.name,
created_at=self.created_at
)
...
And up until a couple weeks ago, if I made any change in the models file, I could run python manage.py db migrate and python manage.py db upgrade and the models were amended and the migration would take place without problems. Now, for whatever reason, when I run the migrate/upgrade commands, nothing happens and it seems that my changes were not recognised at all. Any ideas of why?

SQLAlchemy don't create tables if using Marshmallow

I'm trying to create a project using Flask, Flask-SQLAlchemy, flask-restplus and marshmallow (tried with flask-marshmallow too), but the integration of these tools does not work very well.
Everytime I include some new lib, a new error occur.
I already give up to use migrations with Flask-SQLAlchemy because for some reason, this thing don't work. But now, the problem is with marshmallow.
I'm trying to make with modules and I think this is the part of the problem (all examples of Flask-SQLAlchmey, flask-restplus, flask-marshmallow, etc put everything in a single file)
This is my app.py:
from flask import Flask, Blueprint
import settings
from api import api
from database import init_database, reset_database
app = Flask(__name__)
def configure_app(flask_app):
flask_app.config['SERVER_NAME'] = settings.SERVER_ADDRESS
flask_app.secret_key = settings.SECRET_KEY
def initialize_app(flask_app):
configure_app(flask_app)
blueprint = Blueprint('api', __name__, url_prefix=settings.URL_PREFIX)
api.init_app(blueprint)
# api.add_namespace(auth_login_namespace)
flask_app.register_blueprint(blueprint)
init_database(flask_app)
if settings.DEBUG:
reset_database(flask_app)
def main():
initialize_app(app)
app.run(debug=settings.DEBUG)
if __name__ == '__main__':
main()
api/__init__.py:
import settings
from flask_restplus import Api
api = Api(
version='1.0',
title='Test',
description='Some description'
)
#api.errorhandler
def default_error_handler(e):
message = 'An unhandled exception occurred.'
if not settings.DEBUG:
return {'message': message}, 500
database/__init__.py:
from flask_sqlalchemy import SQLAlchemy
import settings
db = SQLAlchemy()
def init_database(flask_app):
flask_app.config['SQLALCHEMY_DATABASE_URI'] = settings.DATABASE_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
global db # I really don't like this! :(
db = SQLAlchemy(flask_app)
def reset_database(flask_app):
from database.models import User
db.drop_all()
db.create_all()
db.session.add(User(username='admin', email='abc#def.com', name='admin', password='123', admin=True)
db.session.commit()
I have my app, with only one model until now:
database/models/User.py:
from marshmallow import Schema, fields
from sqlalchemy import func
from database import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, index=True)
email = db.Column(db.String(120), unique=True, index=True)
name = db.Column(db.String(200), nullable=False)
password = db.Column(db.String(200), nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
created_on = db.Column(db.DateTime, nullable=False, server_default=func.now())
class UserSchema(Schema):
id = fields.Int(dump_only=True)
username = fields.Str()
email = fields.Email()
name = fields.Str()
password = fields.Str()
admin = fields.Bool()
created_on = fields.DateTime()
now, if I use the following code (this code is called everytime my app start on debug mode, on function reset_database, in file database/__init__.py):
db.drop_all()
db.create_all()
db.session.add(User(username='admin', email='abc#def.com', name='admin', password='123', admin=True)
db.session.commit()
the User table is not created, and the admin is not inserted on table, because the table don't exist (db.create_all() don't create anything).
sqlite3.OperationalError: no such table: user.
For some reason, if I remove the class UserSchema (on database/models/User.py), the db.create_all() function create the table).
Got working right now:
on database/__init__.py, altered the init_database function to:
def init_database(flask_app):
flask_app.config['SQLALCHEMY_DATABASE_URI'] = settings.DATABASE_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(flask_app)
and in database/reset_database.py:
def reset_database(flask_app):
with flask_app.app_context():
from database.models.user_module import User
db.drop_all()
db.create_all()
db.session.add(User(username='admin', email='abc#def.com', name='admin', password='123', admin=True))
db.session.commit()
The problems was the init_app, use the app_context, and I'm importing the wrong User module (tks Fian)

Error "NameError: name 'UsersAdmin' is not defined" when moved all classes to another file

Short story. I took this example:https://github.com/MrJoes/Flask-Admin/tree/master/examples/sqla i played with it and everything was fine until i decided what i want to split app.py(main file) to two parts. In main file app.py i will keep views and in another models.py i will keep all classes. Both files are in same folder.
Issue. I get error Error when running my app.py file:
"NameError: name 'UserAdmin' is not defined"
This is part from app.py file where i try to call Class UserAdmin from models.py file:
import os
import os.path as op
from flask import Flask, render_template, request, redirect, url_for, abort, session, flash
from flask_sqlalchemy import SQLAlchemy, Model
from flask_login import UserMixin, session, LoginManager, login_user, login_required, logout_user
from flask_bcrypt import Bcrypt,check_password_hash,generate_password_hash
from models import *
from flask_admin import Admin, BaseView, expose
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['DATABASE_FILE'] = 'db.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
admin = Admin(app, name='Admin Site', template_mode='bootstrap3')
# Add views. This is where it fails
admin.add_view(UserAdmin(User, db.session))
models.py file where is described UserAdmin part:
from wtforms import validators
from app import db, app, url_for, admin
from flask_admin.contrib import sqla
from flask_admin.contrib.sqla import filters, ModelView
from flask_login import UserMixin
...
# Create models
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(100))
last_name = db.Column(db.String(100))
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
# Required for administrative interface. For python 3 please use __str__ instead.
def __str__(self):
return self.username
class UserInfo(db.Model):
id = db.Column(db.Integer, primary_key=True)
key = db.Column(db.String(64), nullable=False)
value = db.Column(db.String(64))
user_id = db.Column(db.Integer(), db.ForeignKey(User.id))
user = db.relationship(User, backref='info')
def __str__(self):
return '%s - %s' % (self.key, self.value)
class UserAdmin(sqla.ModelView):
inline_models = (UserInfo,)
...
If someone could point me what i am doing wrong there it would be very nice.
Thanks

Categories