Generating table names with same structure but different names - python

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.

Related

SQLAlchemy create_all() unable to create new tables

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()

flask-migrate issue while refactoring code

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()

AttributeError: 'MySQL' object has no attribute 'Model'

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.

Using SQLAlchemy models in and out of Flask

I'm trying to build SQLAlchemy models that can be used in Flask and in other non-Flask services. I know that in order to use these objects in Flask I can use the Flask-SQLAlchemy module and build the models like this:
app_builder.py
def create_app(config):
# Create a Flask app from the passed in settings
app = Flask('web_service')
app.config.from_object(config)
# Attach SQLAlchemy to the application
from database import db
db.init_app(app)
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Job(db.Model):
__tablename__ = 'job'
job_id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(256))
def __init__(self, description):
self.description = description
However it looks like doing this ties the models to using flask_sqlalchemy. I have another service that I would like to use these models in that don't use flask. Is there a way I can reuse these class definitions (maybe by changing db.Model) within a non-Flask specific context?
flask_sqlalchemy doesn`t allow you to use it outside of a Flask context. However, you can create models via SQLAlchemy itself. So your database.py file would look like this:
from sqlalchemy import MetaData, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
metadata = MetaData()
Base = declarative_base(metadata=metadata)
class Job(Base):
__tablename__ = 'job'
job_id = Column(Integer, primary_key=True)
description = Column(String(256))
def __init__(self, description):
self.description = description
You can initialize a flask_sqlalchemy object using produced metadata (flaskdb.py):
from flask_sqlalchemy import SQLAlchemy
from database import metadata
db = SQLAlchemy(metadata=metadata)
And you initialize your Flask app like this:
from flask import Flask
from flaskdb import db
def create_app(config):
app = Flask('web_service')
app.config.from_object(config)
db.init_app(app)
Created models can be used outside of the Flask context via a Session. For example:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from database import metadata, Job
engine = create_engine('your://database#configuration/here')
session = Session(engine)
jobs = session.query(Job).all()
session.close()
As a downside of this approach, you can't use direct access to database objects through models. Instead, you are forced to use Sessions:
from database import Job
from flaskdb import db
Job.query.all() # Does not work
db.session.query(Job).all() # Works

db.create_all() doesn't create tables defined in separate file

I am trying to create the tables for my models, which are defined in a separate module from my app. I call db.create_all(), but no tables are created and there are no errors. I've defined the models and imported them before calling create_all. Why doesn't this work?
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:123#localhost/flask'
db = SQLAlchemy(app)
from models import User
db.create_all()
db.session.commit()
models.py:
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key = True)
You created two separate db instances, one along with the app and one along with the models. Each instance has it's own metadata that stores the tables defined on it. The one you're using to issue the create table statement was not the one that the models were defined on. You should use only one instance of the extension, importing it when needed.
myapp/__init__.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
# import the models *after* the db object is defined
from myapp import models
myapp/models.py:
from myapp import db
class User(db.Model):
...
create_tables.py:
from myapp import app, db
with app.app_context():
db.create_all()
Other things to note:
You should structure your app as a package, so that everything is importable under one location.
flask.ext is deprecated, import the extension directly from its package name.
Flask-SQLAlchemy automatically generates __tablename__ from the class name, you don't need to define it yourself.
You do not have to call commit after create_all.

Categories

Resources