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
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 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
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
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 :)
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"