I recently ran into a DB Lock issue while building my Flask App using a SQLite Database. Apparently there's no real solution to this and from everything I read it seemed the best workaround would be just to switch over to a 'real' database like MySQL OR PostgreSQL. While doing this however I ran into the following problem:
AttributeError: 'MySQL' object has no attribute 'Model'
I guess my issue here is - Im not sure if I configured it properly in my app.py file AND/OR i'm not sure if i'm using the correct 'syntax(?)' in my models.py file. Or possibly it's neither of these things... Either way, I'd immensely appreciate it if someone could look at my code and tell me what's going on ...
Here is my app.py [what's relevent]
from flask import Flask
from flask_mysqldb import MySQL
from flask_bootstrap import Bootstrap
from flask_mail import Mail, Message
from flask_moment import Moment
from flask_login import LoginManager, login_required
from flask_pagedown import PageDown
from flask_migrate import Migrate, MigrateCommand
from flask_sslify import SSLify
from werkzeug.wsgi import DispatcherMiddleware
from flask_script import Manager
server=flask.Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
server.config['SQLALCHEMY_DATABASE_URI'] =
'mysql+pymysql://username:password#localhost/db_name'
server.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
server.config.update(dict(
SECRET_KEY="....",
WTF_CSRF_SECRET_KEY="...."
#SECRET_KEY="powerful secretkey",
#WTF_CSRF_SECRET_KEY="a csrf secret key"
))
manager = Manager(server)
db = MySQL(server)
#db = SQLAlchemy(server) [Old Code]
migrate = Migrate(server, db)
manager.add_command('db', MigrateCommand)
Here is my models.py:
from datetime import datetime
from werkzeug.security import generate_password_hash,
check_password_hash
from flask import request, current_app, url_for
from hashlib import md5
from app import db
from app import login_manager
from flask import request, current_app
from flask_login import UserMixin, AnonymousUserMixin
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
import hashlib
from markdown import markdown
import bleach
from datetime import datetime
class Role(db.Model):
__tablename__ = 'roles'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic')
Any help here would be greatly appreciated !
If you want to use MySQL by SQLAlchemy (Flask-SQLAlchemy), keep the old code for db instance:
# db = MySQL(server) # remove this line and the import for flask_mysqldb
db = SQLAlchemy(server) # keep this and the import for flask_sqlalchemy
Otherwise, if you want to use by Flask-MySQLdb, then you should delete everything comes form SQLAlchemy (Flask-SQLAlchemy), including configuration variables (SQLALCHEMY_DATABASE_URI, SQLALCHEMY_COMMIT_ON_TEARDOWN), imports, db.Model etc.
After that, you should go to read Flask-MySQLdb's documentation to learn how to use it.
Related
I have flask web app which uses mysql db using flask-sqlalchemy.
I have kept separate utility scripts for DDL creation.
My existing app works perfectly fine but this script is unable to create new table.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import connect_strng
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = connect_string
db = SQLAlchemy()
# Added this import just before create_all
from db_models import Test
db.create_all()
db.session.commit()
I have defined model inside db_models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Test(db.Model):
__tablename__ = 'test'
test_id = db.Column(db.Integer, primary_key=True)
My script is finishing with exit code of 0 indicating no errors, but I don't see table getting generated in mysql database.
$ python create_table.py
$ echo $?
0
I checked answer to the similar question but did not work.
You need to use the same db object across your whole app. Importing it where it is needed.
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # <--- This is what is causing your issue
# IT should look something more like...
from create_table import db
class Test(db.Model):
__tablename__ = 'test'
test_id = db.Column(db.Integer, primary_key=True)
However there is a problem with the above suggestion...It will lead to a circular import. To solve that requires restructuring your app a bit. Exactly how to do it is up to you but I'll give you a suggestion.
Create a new file called database.py and put your db object in there. Then you can do from database import db whenever you need db.
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
As far as how to structure your app, consider the application factory pattern. It takes into account the circular import issue that commonly arises with flask.
I was able to resolve the issue by making use of flask's application context.
As sugested by #noslenkwah, you should use db object from single place by defining into single file database.py.
Here is my solution.
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
db_models.py
from database import db
class Test(db.Model):
__tablename__ = 'test'
test_id = db.Column(db.Integer, primary_key=True)
create_table.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import connect_strng
from database import db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = connect_string
with app.app_context():
db.init_app(app)
# Added this import just beore create_all
from db_models import Test, CrawlStat
db.create_all()
db.session.commit()
Hi guys i am trying to implement MVC pattern in my flask rest API application but I am facing some issues like flask migration and writing scalable code.
For flask migration I'm not able to detect models while migrating to mysql.
Following is my sample app architecture
This is the models/ini.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
And this is my models/user_master.py
import dataclasses
import flask_bcrypt
from . import db
# from sqlalchemy_utils import PhoneNumber
#dataclasses
class UserTypeMaster(db.Model):
__tablename__ = 'UserTypeMaster'
def __init__(self, _id, _type):
self.id = _id
self.type = _type
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
type = db.Column(db.String(20), unique=True, nullable=False)
This is my centuryApi.py file
from flask import Flask
from flask_migrate import Migrate
from config import config_names
from models import db
from flask_sqlalchemy import SQLAlchemy
from routes.user_route import user_bp
app = Flask(__name__)
app.config.from_object(config_names['default'])
app.config.from_pyfile('config.py')
db.init_app(app)
migrate = Migrate()
migrate.init_app(app, db)
from models.user_master import UserMaster
from models.address_master import CityMaster, StateMaster, CountryMaster
app.register_blueprint(user_bp, url_prefix='/users')
#app.route('/')
def index():
return "Hello"
if __name__ == '__main__':
app.run()
And if I don't include models after initializing migrate object and run flask db migrate I get following:
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.env] No changes in schema detected.
And when including models i get following error:
File "/home/abhishek/FreeLance/Century/centuryApi/centuryApi.py", line 17, in
from models.user_master import UserMaster
File "/home/abhishek/FreeLance/Century/centuryApi/models/user_master.py", line 9, in
class UserTypeMaster(db.Model):
TypeError: 'module' object is not callable
I'm not getting where my reference is wrongly assigned on line 9 in user_master.py
Also i need suggestion regarding this architecture and how can improvise more to make it more scalable.
Any help will be appreciated.
Thanks
I am facing an issue where my app is not able to recognise '#login_manager' decorator even though I have imported login_manager object created from extensions.py. I tried to debug the issue by printing out the package extensions that are configured in the app and it seems that login_manager is not included. Maybe that could be the cause of the failure. I have also read through this posted question, but I felt it wasn't a satisfying answer. Given that login_manager.init(app), is recommended in the official documentation found here.
Hope someone who is really experience in flask to be able to help me out here. Thank you!
app.py
from flask_login import login_required, current_user
from flask import Flask, render_template,request
from amazonreviews import main_func as m
import os
import json
def create_app():
app = Flask(__name__)
with app.app_context():
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://///somepath/abc.sqlite3'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.secret_key = os.urandom(24)
#Initialise extensions
register_extensions(app)
return app
def register_extensions(app):
from extensions import db
from extensions import migrate
from extensions import login_manager
db.init_app(app)
migrate.init_app(app,db)
login_manager.init_app(app)
for key in app.extensions:
print(key)
app = create_app()
#A user loader tells Flask-Login how to find a specific user from the ID that is stored in their session cookie
#login_manager.user_loader
def load_user(user_id):
from model import User
# since the user_id is just the primary key of our user table, use it in the query for the user
return User.query.get(int(user_id))
extensions.py
#Import external packages and create external objects
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
migrate = Migrate()
db = SQLAlchemy()
login_manager = LoginManager()
Print key from extension output:
#login_manager decorator not recognised:
In that code, login_manager isn't defined until register_extensions is called.
Assuming the instance of login_manager is created in extensions, you might be able to hoist the import up to the top. E.g.,
import json
from extensions import login_manager
...
#login_manager.user_loader
...
I am creating a forex application.I want to create the same schema but create different tables with the same schema according to the currency pairs.I searched for this on google and here too.No case matches my requirement.I am using Flask_sqlalchemy for the database ORM and postgres as my database.
app/init.py
from flask import Flask
from flask_mongoengine import MongoEngine
from app.config import Config
from flask_restful import Api
from flask_jwt_extended import JWTManager
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
app=Flask(__name__)
app.config.from_object(Config)
dbs=SQLAlchemy(app)
migrate=Migrate(db=dbs,app=app)
jwt=JWTManager(app)
db=MongoEngine(app)
api=Api(app)
from app import errors,models,resources
api.add_resource(resources.CourseListResource,'/api/v1.0/courses',endpoint="courses")
api.add_resource(resources.CourseResource,'/api/v1.0/courses/<string:name>',endpoint="course")
api.add_resource(resources.UserRegistration,'/api/v1.0/register')
api.add_resource(resources.UserLogin,'/api/v1.0/login')
api.add_resource(resources.UserLogoutAccess, '/api/v1.0/logout/access')
api.add_resource(resources.UserLogoutRefresh, '/api/v1.0/logout/refresh')
api.add_resource(resources.TokenRefresh, '/api/v1.0/token/refresh')
app/config.py
import os
class Config():
SECRET_KEY = os.environ.get('SECRET_KEY') or 'mysecretkey'
MONGODB_SETTINGS = {"DB": "pmong"}
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or "postgresql://localhost/test"
#sqlite_db_path=sqlite:///" + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
app/models.py
from app import dbs
class Forex(dbs.Model):
id = dbs.Column(dbs.Integer, primary_key=True)
time = dbs.Column(dbs.DateTime, unique=True, nullable=False)
high = dbs.Column(dbs.Float, nullable=True)
low=dbs.Column(dbs.Float,nullable=True)
open=dbs.Column(dbs.Float,nullable=True)
close=dbs.Column(dbs.Float,nullable=True)
volume=dbs.Column(dbs.Integer,nullable=True)
def save_to_db(self):
dbs.session.add(self)
dbs.session.commit()
Currently I have not given the table name.I should be able to create different table name for this schema and manipulate it as well.I cannot find a way to create dynamic tables for each currency pair.
I got the below file structure for a Python-Flask app with flask-migrate :
My issues are
1-I'm unable to use db and create_app inside manage.py
When I do:
$ python manage.py db init
I got below error:
File "/app/main/model/model.py", line 25, in <module>
class User(db.Model):
NameError: name 'db' is not defined
(db is defined in main.init.py )
I have tried different options with no success.
I want to keep the manage.py , model.py and main.init.py in separate files.
2- In model .py I will need db .How will I make db available to model.py ?
Here below is manage.py
# This file take care of the migrations
# in model.py we have our tables
import os
import unittest
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from app.main import create_app
from app.main import db
# # We import the tables into the migrate tool
from app.main.model import model
app = create_app(os.getenv('BOILERPLATE_ENV') or 'dev')
app.app_context().push()
manager = Manager(app)
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
#### If I add model.py here all should be easier , but still I have the
#### issue with
#### from app.main import create_app , db
#manager.command
def run():
app.run()
#manager.command
def test():
"""Runs the unit tests."""
tests = unittest.TestLoader().discover('app/test', pattern='test*.py')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
return 0
return 1
if __name__ == '__main__':
manager.run()
This is app.init.py where db and create_app are defined
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_cors import CORS
from .config import config_by_name
from flask_restful import Resource, Api
# from flask_restplus import Resource
from app.main.controller.api_controller import gconnect, \
showLogin, createNewTest, getTest, getTests, getIssue, createNewIssue
db = SQLAlchemy()
flask_bcrypt = Bcrypt()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_by_name[config_name])
cors = CORS(app,
supports_credentials=True,
resources={r"/api/*":
{"origins":
["http://localhost:3000",
"http://127.0.0.1:3000"]}})
api = Api(app)
db.init_app(app)
flask_bcrypt.init_app(app)
api.add_resource(gconnect, '/api/gconnect')
api.add_resource(showLogin, '/login')
api.add_resource(createNewTest, '/api/test')
api.add_resource(getTest, '/api/test/<int:test_id>')
api.add_resource(getTests, '/api/tests')
api.add_resource(getIssue, '/api/issue/<int:issue_id>')
api.add_resource(createNewIssue, '/api/issue')
return app
And this is (just one of the table for simplicity) of my model
from sqlalchemy import Column, ForeignKey, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref
from sqlalchemy import create_engine
from sqlalchemy.sql import func
# # # This will let sql alchemy know that these clasess
# # # are special Alchemy classes
# Base = declarative_base()
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(250), nullable=False)
email = db.Column(db.String(250), nullable=False)
pictures = db.Column(db.String(250))
role = db.Column(db.String(25), nullable=True)
My issues are:
1-I'm unable to use db and create_app inside manage.py
When I do:
$ python manage.py db init
I got below error:
File "/app/main/model/model.py", line 25, in
class User(db.Model):
NameError: name 'db' is not defined
(db is defined in main.init.py )
I have tried different options with no success.
I want to keep the manage.py , model.py and main.init.py in separate files.
2- In model .py I will need db .How will I make db available to model.py ?
A simple solution is to create a seperate initializtions file besides your __init__.py. e.g. init.py where you initialize sqlalchemy along with other extensions. That way they can be imported in all the modules without any circular dependencies problems.
A more elegant solution however is to you use Flask's current_app and g proxies. They were made to help Flask users circumvent any problems with circular dependencies.
Typically you initalize the flask app in the __init__.py module and the __init__.py module sometimes has to import some variables from its sub-modules. This becomes problematic when sub-modules try to import initalized extensions
As a general rule of thumb, outer modules should be importing from their submodules not the other way around.
So here's one way you can solve your problem (cited from here):
** __init__.py
from flask import g
def get_db():
if 'db' not in g:
g.db = connect_to_database()
return g.db
#app.teardown_appcontext
def teardown_db():
db = g.pop('db', None)
if db is not None:
db.close()
def init_db():
db = get_db()
Now you can easily import your db connection into any other module by:
from flask import g
db = g.db
db.do_something()