Import an SQLAlchemy table to a pandas dataframe without Flask - python

I am creating a server application that will utilize a remote database created by a Flask GUI. To keep things simple (and since it's primarily threaded calculations), I want to build my server application without utilizing a Flask framework. I will have a redis message server to keep the two processes in sync.
My challenge is that I want to use persistent storage wherever possible. So as part of this, my server application will need to import the Flask-SQLAlchemy database files to retrieve the parameters. The difficulty I am having is to write the import statement that will pull the SQLAlchemy files into pandas. Here is what I have so far:
config.py
import os
class Config:
SQLALCHEMY_DATABASE_URI_REMOTE = os.environ.get('RDQ_LOGIN') # remote docker database
SQLALCHEMY_DATABASE_URI_LOCAL = os.environ.get('RDU_LOGIN') # local file database
REDIS_IP = os.environ.get('REDIS_IP')
REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD')
init.py
from src_code.config import Config
import redis
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base
import sqlalchemy as sa
engine_remote = create_engine(Config.SQLALCHEMY_DATABASE_URI_REMOTE, echo=True)
Base_remote = declarative_base()
Base_remote.metadata.create_all(engine_remote)
Session_remote = sessionmaker(bind=engine_remote)
Session_remote.configure(bind=engine_remote)
session_remote = Session_remote()
engine_local = create_engine(Config.SQLALCHEMY_DATABASE_URI_LOCAL, echo=True)
Base_local = declarative_base()
Base_local.metadata.create_all(engine_local)
Session_local = sessionmaker(bind=engine_local)
Session_local.configure(bind=engine_local)
session_local = Session_local()
redisChannel = redis.StrictRedis(host=Config.REDIS_IP, port=6379, password=Config.REDIS_PASSWORD,
decode_responses=True)
main.py
import pandas as pd
from src_code import session_local, session_remote
def start():
table_df = pd.read_sql(
'SELECT * from game',
con=session_remote
)
print(table_df)
if __name__ == "__main__":
start()
Unfortunately I am getting an error:
AttributeError: 'Session' object has no attribute 'cursor'
I don't need to be able to write back to the table (so read-only is sufficient). So I am using a simple example that would give me the ability to extract what I need from the panda (I am more confident to use pandas than SQL).
I do have the model statements that I could replicate in the server code if this would somehow facilitate the process:
from datetime import datetime
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
from src_code import db, login_manager
from flask_login import UserMixin
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
agent = db.Column(db.Integer, unique=False, nullable=False)
image_file = db.Column(db.String(20), unique=False, nullable=False,default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
games_started = db.relationship('Game', backref='captained', lazy=True)
games_played = db.relationship('Player', backref='games', lazy=True)
def get_reset_token(self, expires_sec=1800):
s = Serializer(current_app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id}).decode('utf-8')
#staticmethod
def verify_reset_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.agent}', '{self.image_file}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False,default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
class Game(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(60), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
company_count = db.Column(db.Integer, nullable=False)
starting_year = db.Column(db.Integer, nullable=False)
time_limit = db.Column(db.Integer, nullable=False)
agent_decisions_visible = db.Column(db.Boolean, nullable=False)
client_count = db.Column(db.Integer, nullable=False)
pre_game_yrs = db.Column(db.Integer, nullable=False)
time_index = db.Column(db.Integer, nullable=False)
game_active = db.Column(db.Boolean, nullable=False)
player_capt = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
games_msgs = db.relationship('Messages', backref='messages', lazy=True)
def __repr__(self):
return f"Game('{self.title}', '{self.date_posted}')"
class GameRequests(db.Model):
id = db.Column(db.Integer, primary_key=True)
date_requested = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
game_id = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"GameRequest('{self.game_id}', '{self.user_id}', '{self.date_requested}'"
class GameDecisions(db.Model):
id = db.Column(db.Integer, primary_key=True)
date_requested = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
game_id = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
time_index = db.Column(db.Integer, nullable=False)
def __repr__(self):
return f"GameDecisions('{self.game_id}', '{self.user_id}', '{self.time_index}'"
class Player(db.Model):
id = db.Column(db.Integer, primary_key=True)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
game_id = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Player('{self.game_id}', '{self.user_id}', '{self.date_posted}'"
class Messages(db.Model):
id = db.Column(db.Integer, primary_key=True)
date_posted = db.Column(db.DateTime, nullable=False,default=datetime.utcnow)
type = db.Column(db.String(10), nullable=False)
msg_from = db.Column(db.String(20), nullable=False)
msg_to = db.Column(db.String(20), nullable=False)
message = db.Column(db.String(60), nullable=False)
game_id = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False)
def __repr__(self):
return f"Messages('{self.game_id}', '{self.id}', '{self.message}', '{self.date_posted}')"
Thanks for any help you can offer!

Similar to your conclusion, here's how I read databases into pandas:
# Create your query.
# This can be as complex or simple as you'd like
query = session_remote.query(Game)
df = pd.read_sql(query.statement, session_remote.bind)
The key difference here is the utilization of the ORM to perform (or rather, write) the query itself.
Masking SQL behind an ORM has many advantages -- I strongly recommend against utilizing raw SQL in production backends.

It seems I was closer than I realized. The following code did what I needed:
SQLAlchemy ORM conversion to pandas DataFrame
table_df = pd.read_sql(
'SELECT * from game',
session_remote.bind
)

Related

I am getting sqlalchemy.exc.InvalidRequestError in my pythonanywhere error log. How can I fix it?

from yff import db, login_manager, app
from flask_login import UserMixin
import datetime
import jwt
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
password = db.Column(db.String(120), unique=False, nullable=False)
email = db.Column(db.String(50), unique=False, nullable=False)
profile_pic = db.Column(db.String(30), unique=False, default="default.jpg")
is_moderator = db.Column(db.Boolean, default=False)
posts = db.relationship('Posts', backref='author', lazy=True)
likes = db.relationship('Likes', backref='user', passive_deletes=True)
comments = db.relationship('Comment', backref='user', passive_deletes=True)
def get_reset_token(self):
encoded = jwt.encode({'user_id':self.id, "exp":datetime.datetime.now() + datetime.timedelta(hours = 0.5)}, app.config['SECRET_KEY'], algorithm='HS256')
return encoded
#staticmethod
def verify_secret_token(token):
try:
decoded = jwt.decode(token, options={"verify_signature": False})
user_id = decoded['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f'{self.username}, {self.email}'
class Image(db.Model):
id = db.Column(db.Integer, primary_key=True)
title=db.Column(db.String(120), nullable=False)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now(tz=datetime.timezone.utc))
img_location = db.Column(db.String(600), nullable=False)
mimetype = db.Column(db.String(10))
post_name = db.Column(db.String(150),nullable=False, unique=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
manga_name = db.Column(db.String(100), unique=False, nullable=False)
class Posts(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('image.id', ondelete="CASCADE"), nullable=False)
likes = db.Column(db.Integer, db.ForeignKey('likes.id', ondelete='CASCADE'))
date_created = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now(tz=datetime.timezone.utc))
comments = db.relationship('Comment', backref='Posts', passive_deletes=True)
class Likes(db.Model):
id = db.Column(db.Integer, primary_key=True)
author = db.Column(db.Integer, db.ForeignKey('user.id', ondelete="CASCADE"), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('image.id', ondelete="CASCADE"), nullable=False)
liked_post = db.relationship('Posts', backref='post')
class Comment(db.Model): #import it in the __init__ file
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(1000), nullable=False)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.datetime.now(tz=datetime.timezone.utc))
author = db.Column(db.Integer, db.ForeignKey('user.id', ondelete="CASCADE"), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('image.id', ondelete="CASCADE"), nullable=False)
The following is the entire error:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class Posts->posts'. Original exception was: Could not determine join condition between parent/child tables on relationship Posts.comments - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
I am getting this error in the pythonanywhere error log. I tried changing the positions of the backref statement but I that did not help. (I am new to web dev and I still haven't figured out how backref works)
I know how foreign keys work in SQL but I am still not experienced at OOP and SQLAlchemy, so please help me out.

Trying to create database using Flask-SQLAlchemy

Trying to create a databases using the flask-SQLAlchemy module. When I insert this code into the command line "from sqlalchemy import db".
I get this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\andre\AppData\Local\Programs\Python\Python38\sqlalchemy.py", line 1
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit (AMD64)] on win32
^
SyntaxError: invalid syntax.
Here is my code:
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']= 'sqlite:///site.db'
db = SQLAlchemy(app)
class User(db.model):
id = db.Column(db.integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file=
db.Column(db.String(20),nullable=False,default='default.jpg')
password = db.Column(db.String(60), nullabale=False)
posts= db.relationship('Post', backref='author', lazy = True)
def __repr__(self):
return f"User('{self.username}', '{self.email}',
'{self.image_file}')"
class post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False,
default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'),
nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
Could someone please help me? I've been stuck on this quite some time. I've installed flask-SQLAlchemy and updated my pip. Don't know what else to do really.
You had some typos in the code and not sure regarding that image_file= line so removed that line for now, follow the below code it would provide u with db
edited: didnt saw that image file one line updated it can you check
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file=db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}','{self.image_file}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
db.create_all() # this create the site.db

Database Table Schema not creating with flask sqlalchemy ORM package

I'm trying to create to blog but I'm having issues creating database using sqlite as my database engine in which I created classes to define each table schema using an ORM with flask-sqlalchemy and also another thing I noticed was it created an empty blog.db file. I cant solve the issue im having right now. As of now this is my resort for help before using Firebase.
models.py
from blogent import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(50), nullable=False)
last_name = db.Column(db.String(50), nullable=False)
email = db.column(db.String(50), unique=True, nullable=False)
image = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(50), nullable=False)
post = db.relationship('Post', backref='author', lazy=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow())
updated_at = db.Column(db.DateTime, default=datetime.utcnow())
def __repr__(self):
return f"User('{self.email}', '{self.image}', '{self.created_at}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
post_name = db.Column(db.String(30), nullable=False)
post_title = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
comments = db.relationship('Comments', backref='posts', lazy=True)
user = db.relationship('User', backref='users', lazy=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow())
updated_at = db.Column(db.DateTime, default=datetime.utcnow())
def __repr__(self):
return f"Post('{self.post_name}', '{self.post_title}', '{self.created_at}')"
class Comments(db.Model):
id = db.Column(db.Integer, primary_key=True)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
content = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow())
updated_at = db.Column(db.DateTime, default=datetime.utcnow())
def __repr__(self):
return f"Comments('{self.content}', '{self.created_at}')"
init.py
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///blog.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
app.config['SECRET_KEY'] = '48ea69eb3539fbe7e069deee6c74d46d'
db = SQLAlchemy(app)
#app.before_first_request
def create_tables():
db.create_all()
from blogent import routes

Cannot create user in database: sqlalchemy.exc.InvalidRequestError

I am trying to add an user to the database file but i get the following error when trying to create an User object:
sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class Patient->patient'. Original exception was: Could not determine join condition between parent/child tables on relationship Patient.documents - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
from flask import Flask, render_template, flash
from flask_sqlalchemy import SQLAlchemy
from forms import LoginForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'SECRETKEY'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///storage.db'
db = SQLAlchemy(app)
"""
Users
"""
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
username = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
mail = db.Column(db.String, default='test#mail')
role = db.Column(db.Integer)
def __repr__(self):
return f"User('{self.username}', '{self.name}')"
"""
Patients
"""
class Patient(db.Model):
id = db.Column(db.Integer, primary_key=True)
prename = db.Column(db.String, nullable=False)
name = db.Column(db.String, nullable=False)
mail = db.Column(db.String, default='test#mail')
birthdate = db.Column(db.String, nullable=False)
documents = db.relationship('Doc', backref='patient', lazy=True)
def __repr__(self):
return f"Patient('{self.prename}', '{self.name}')"
"""
Documents
"""
class Doc(db.Model):
from datetime import datetime
pdfid = db.Column(db.Integer, primary_key=True)
path = db.Column(db.String)
created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
deletetime = db.Column(db.Integer, nullable=False)
patientid = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Docs('{self.path}', '{self.created}')"
My Steps in a python Terminal (the file is called index):
from index import db
db.create_all()
from index import User, Doc, Patient
user1 = User(name='Test User', username='test', password='testtest', role=1)
When I try step 4 I get the above described error.
I don't see any problem in my code so I would appreciate any help :)

How to add flask-RBAC models to existing SQLAlchemy database

I'm trying to add RBAC to my existing flask application where I already have 2 models which describe User and Post model respectively. Here is my code:
# models.py
from datetime import datetime
from rpd_site import db, login_manager
from flask_login import UserMixin
# []
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Main site account table
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
confirmed = db.Column(db.Boolean, nullable=False, default=0)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.confirmed}')"
# Posts table
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.now) # current local time instead of .utcnow
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default_post.png')
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}', '{self.content[:15]}')"
When I tried add all missing code from here I faced with lots of errors. Especially I'm not sure if I should import UserMixin from flask_rbac or from flask_login.
Help me to understand how can I upgrade my DB with RBAC functionality.
This is a very broad question, I'll try to give you a minimum code so that you can achieve RBAC. Below example uses Flask-security.
from app import db
from flask_security import RoleMixin, UserMixin
# may to many association table between User and Role
roles_users = db.Table(
'roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
)
class Role(db.Model, RoleMixin):
__tablename__ = 'role'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)
def __str__(self):
return self.name
class User(db.Model, UserMixin):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50), unique=True)
password = db.Column(db.String(255))
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='joined'))
def __str__(self):
return self.email
You either migrate or create the DB based on above Models. The above will be sufficient for you to either perform back-end operation for RDBC or at view level.
You can then assign roles to each user easily using below link.
Flask-security create role,user and linking user_id to role_id
If you want to perform RBAC at view, follow below.
from flask_security import login_required, roles_accepted
#app.route('/a_restricted_view/')
#login_required
#roles_accepted('role_one', 'role_two')
def a_restricted_view():
return "I am only visible to users with role_one and role_two"

Categories

Resources