I am trying to create a basic blog post website. Everything was going fine until i tried to run the app and it showed me the error:-
"Exception: Missing user_loader or request_loader"
but I have already created the user_loader. so I tried to find solutions and in the process I found that flask db migrate is not creating any table. so I searched online and found a solution to add all my tables in evn.py file in migration folder. I thought that was the problem and I tried to run the app again and this appeared again:-
"Exception: Missing user_loader or request_loader"
This is my __init__py file
# blogpost/__init__.py
import os
import secrets
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(8)
# DATABASE CONFIGURATION #############
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
# LOGIN CONFIGURATION #################
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
# IMPORTING BLUEPRINTS #################################
from blogpost.core.views import core
from blogpost.user.views import users
# BLUEPRINTS CONFIGURATION #################################
app.register_blueprint(core)
app.register_blueprint(users)
and this is my models.py file.
from blogpost import db, login_manager
from flask_login import UserMixin
from datetime import datetime
from werkzeug.security import check_password_hash, generate_password_hash
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
fav_posts = db.Table('fav_posts',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('fav_posts_id', db.Integer, db.ForeignKey('posts.id')))
follows = db.Table('follows',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('follows', db.Integer, db.ForeignKey('users.id')))
fav_tags = db.Table('fav_tags',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('fav_tags_id', db.Integer, db.ForeignKey('tags.id')))
licked_posts = db.Table('licked_posts',
db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
db.Column('user_id', db.Integer, db.ForeignKey('users.id')))
tags_included = db.Table('tags_included',
db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
db.Column('user_id', db.Integer, db.ForeignKey('tags.id')))
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
email = db.Column(db.String, unique=True, index=True)
dob = db.Column(db.Date)
password_hash = db.Column(db.String)
account_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
profile_image = db.Column(db.String)
is_verified = db.Column(db.Boolean, default=False)
posts = db.relationship('Post', backref='author', lazy=True)
favorite_posts = db.relationship('Post', secondary=fav_posts, backref=db.backref('fav_by', lazy='dynamic'))
followers = db.relationship('User', secondary=follows, backref=db.backref('following', lazy='dynamic'))
favorite_tags = db.relationship('Tag', secondary=fav_tags, backref=db.backref('users', lazy='dynamic'))
def __init__(self, email, password, username, dob):
self.email = email
self.username = username
self.dob = dob
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.Text)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
likes = db.relationship('User', secondary=licked_posts, backref=db.backref('licked_by', lazy='dynamic'))
tags_includes = db.relationship('Tag', secondary=tags_included,
backref=db.backref('post_including_tag', lazy='dynamic'))
def __init__(self, title, body):
self.title = title
self.body = body
class Tag(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
def __init__(self, name):
self.name = name
can anyone one tell me what should I do to solve this and more importantly what is the cause because I have done same in my previous project but this never happened.
UPDATE:-
I've solved this problem by creating my user_loader inside my init file after the login_manager.login_view = 'users.login' file. I imported the User model after this line and then created the user_loader.
so my guess is that the problem is that flask is not able to find the "models.py" file. if anyone can explain the problem accurately or have a better solution you're most welcome (^-^)
here is another work i did for practice and it worked fine.
#puppycompanyblog/__init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
#DATABASE SETUP##########################
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir,'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATION'] = False
db = SQLAlchemy(app)
Migrate(app,db)
#########################################
#LOGIN CONFIGURATIONS####################
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
#########################################
from puppycompanyblog.core.views import core
from puppycompanyblog.users.views import users
from puppycompanyblog.blog_posts.views import blog_posts
from puppycompanyblog.error_pages.handlers import error_pages
app.register_blueprint(core)
app.register_blueprint(users)
app.register_blueprint(blog_posts)
app.register_blueprint(error_pages)
and
# puppycompanyblog/models.py
from puppycompanyblog import db, login_manager
from werkzeug.security import check_password_hash, generate_password_hash
from flask_login import UserMixin
from datetime import datetime
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
profile_image = db.Column(db.String(64), nullable=False, default='default_profile.png')
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('BlogPost', backref='author', lazy=True)
def __init__(self, email, username, password, ):
self.email = email
self.username = username
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def __repr__(self):
return f"username: {self.username}"
class BlogPost(db.Model):
users = db.relationship(User)
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
title = db.Column(db.String(140), nullable=False)
text = db.Column(db.Text, nullable=False)
def __init__(self, title, text, user_id):
self.title = title
self.text = text
self.user_id = user_id
def __repr__(self):
return f"Post ID: {self.id} -- Date: {self.date} --- {self.title}"
The reason why the user_loader function isn't found is because you are not importing the module in which it is defined. You put it in models.py, so you need to import this module somewhere in the area where you define your application, so that the handler is registered with the Flask-Login extension. You'll also need to import this file so that Flask-SQLAlchemy registers your models.
Based on the code that you posted, you could add import models at the bottom of blogpost/__init__.py and I think that should do it (it needs to be at the bottom to prevent circular imports).
Related
I am writing an app that has 3 users: Super Admin, Admin, and Students. the Super Admin and Admin have the same functionalities except for some pages that are restricted for the admin, they have the same login credentials. (name and password ).
The student uses matricule number and password to log in.
Here is how I set the login_manager.login_view:
login = LoginManager()
login.login_views = 'admin.sperAdminLogin'
login.login_views = 'students.studentLogin'
However when I log in as a student it works, but when I open up a new window and access the super admin login page I am directly redirected to his home page without entering the credentials.
How can I set the login_view to handle this?
I am using flask blueprint I have an admin blueprint for both super admin and admin and a Student blueprint.
Here is my code :
The main init.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_migrate import Migrate
from flask_login import LoginManager
db = SQLAlchemy()
migrate = Migrate()
login = LoginManager()
login.login_view = 'admin.sperAdminLogin'
login.login_view = 'students.studentLogin'
login.login_message = "Veuillez vous connecter pour accéder à cette page."
login.login_message_category = 'info'
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db, render_as_batch=True)
login.init_app(app)
# Registering blueprints
from sgp.errors import bp as errors_bp
app.register_blueprint(errors_bp)
from sgp.admin import bp as admin_bp
app.register_blueprint(admin_bp, url_prefix='/admin')
from sgp.students import bp as students_bp
app.register_blueprint(students_bp, url_prefix='/students')
from sgp.main import bp as bp
app.register_blueprint(bp)
return app
# Avoiding the circular import
from sgp import models
The model.py
from hashlib import md5
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from flask import session
from flask_login import UserMixin
from sqlalchemy import ForeignKey
from sgp import db, login
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20),index=True, nullable=False)
first_name = db.Column(db.String(20), index=True, nullable=False)
last_name = db.Column(db.String(20), index=True, nullable=False)
email = db.Column(db.String(120), unique=True, index=True, nullable=False)
phone_number = db.Column(db.String(10), unique=True)
profile_pic = db.Column(db.String(20), nullable=False, default="default.jpg")
password_hash = db.Column(db.String(128), nullable=False)
status = db.Column(db.Boolean(), default=False)
type = db.Column(db.String(50))
__mapper_args__ = {
'polymorphic_identity':'user',
'polymorphic_on':type,
}
def set_password(self, password):
"""Take in self keyword and password and return the passwordhash"""
self.password_hash = generate_password_hash(password)
def check_password(self, password):
"""Take in self and password and returns True or false"""
return check_password_hash(self.password_hash, password)
class SuperAdmin(User):
__tablename__= 'superadmin'
id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
bordereaux = db.relationship("Bordereau", backref="superadmin", lazy="dynamic")
Payment_plans = db.relationship("PaymentPlan", backref="superadmin")
Payments = db.relationship("Payment", backref="superadmin", lazy="dynamic")
__mapper_args__ = {
'polymorphic_identity':'superadmin'
}
def __repr__(self):
"""
Takes in the keyword self and returns the instance of the super admin class
And it herited atributes
"""
return (
'Super-Admin, First-name %s, Last-name %s, Email %s'
'Gender %s, Login-time %s'
% (
self.first_name,
self.last_name,
self.email,
self.gender,
self.login_at,
)
)
class Student(User):
id : primary key & foreignkey
the id for the student user
gender : enum
the gender of the user
login_at : datetime
the login date and time the user was loged in to the system
date_of_birth : date
the date of birth of the user
creation_date : datetime
the date and time the use was created
student_matricule : int
the maricule of the student user
student_faculty : str
the faculty of the student
student_promotion : str
the promotion of the student user
"""
__tablename__= 'student'
id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
gender = db.Column(db.Enum("H", "F", "Au", name="varchar"))
login_at = db.Column(db.DateTime())
date_of_birth = db.Column(db.Date())
creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
matricule = db.Column(db.Integer, unique=True, nullable=False)
faculty = db.Column(db.String(20))
promotion = db.Column(db.String(20))
bordereaux = db.relationship("Bordereau", backref="student", lazy="dynamic")
__mapper_args__ = {
'polymorphic_identity':'student',
}
def avatar(self, size):
digest = md5(self.email.lower().encode('utf-8')).hexdigest()
return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format(
digest, size)
class AccademicYear(db.Model):
___tablename__ = 'accademic_year'
id = db.Column(db.Integer, primary_key=True)
starting_date = db.Column(db.Date(), nullable=False)
ending_date = db.Column(db.Date(), nullable=False)
bordereaux = db.relationship("Bordereau", backref="accademic_year", lazy="dynamic")
Payment_plans = db.relationship("PaymentPlan", backref="accademic_year", lazy="dynamic")
Payments = db.relationship("Payment", backref="accademic_year", lazy="dynamic")
class Bordereau(db.Model):
__tablename__ = 'bordereau'
id = db.Column(db.Integer, primary_key=True)
bordereau_code = db.Column(db.String(6), nullable=True)
bordereau_img = db.Column(db.String(20), nullable=False, default="bordereau.jpg")
payment_motif = db.Column(db.String(20), nullable=False)
timestamp = db.Column(db.DateTime())
Sending_time = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
super_admin_id = db.Column(db.Integer, db.ForeignKey("superadmin.id"))
student_id = db.Column(db.Integer, db.ForeignKey("student.id"))
accademic_year_id = db.Column(db.Integer, db.ForeignKey("accademic_year.id"))
class PaymentPlan(db.Model):
__tablename__ = 'paymentplan'
id = db.Column(db.Integer, primary_key=True)
payment_name = db.Column(db.String(20), unique=True, nullable=False)
payment_amount = db.Column(db.Numeric(), nullable=False)
payment_schadule = db.Column(db.Date(), nullable=False)
timestamp = db.Column(db.DateTime)
super_admin_id = db.Column(db.Integer, db.ForeignKey("superadmin.id"))
accademic_year_id = db.Column(db.Integer, db.ForeignKey("accademic_year.id"))
class Payment(db.Model):
__tablename__ = 'payment'
id = db.Column(db.Integer, primary_key=True)
matricule = db.Column(db.Integer, nullable=False)
amount = db.Column(db.Numeric(), nullable=False)
payment_motif = db.Column(db.String(20), nullable=False)
payment_type = db.Column(db.String(20), nullable=False)
carancy = db.Column(db.String())
register_time = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
timestamp = db.Column(db.DateTime)
super_admin_id = db.Column(db.Integer, db.ForeignKey("superadmin.id"))
accademic_year_id = db.Column(db.Integer, ForeignKey("accademic_year.id"))
#login.user_loader
def user_loader(id):
return User.query.get(id)
3.The super admin and student login form
class sperAdminLoginForm(FlaskForm):
"""A class to represent super admin login form"""
userName = StringField('Username',
validators=[DataRequired()])
# email = StringField('Email ou Username',
# validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
# Secure cookie for keeping the user stay loged in for while
remember_me = BooleanField('Remember Me')
submit = SubmitField('Se connecter')
class studentLoginForm(FlaskForm):
"""A class to represent student login form"""
matricule = StringField('Matricule',
validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
# Secure cookie for keeping the user stay loged in for while
remember = BooleanField('Remember Me')
submit = SubmitField('Se connecter')
i'm trying to make a jwt authentication, but every video and post that i see just use jsonify, none of them use render_template with login required, i searched a lot but didn't find anything that helps me, could you guys please help me to do this?
I want to after the user logging in correctly the next page check if the jwt it is correctly, if it is it will load the page, if it doesn't it won't load the page that is protectd with the login required decorator.
Bellow is the code. Thanks in advance.
from flask import Flask, render_template, redirect, url_for, jsonify, request, session, make_response
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
import os
from flask_sqlalchemy import SQLAlchemy
import hashlib
from flask_login import LoginManager, UserMixin, login_required, login_user
import jwt
from datetime import datetime, timedelta
from functools import wraps
app = Flask(__name__)
app.config["SECRET_KEY"] = os.urandom(12)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:Bambam&xx12#localhost/mobbi"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = "render_login"
class LoginForm(FlaskForm):
login = StringField("Login", validators=[DataRequired()])
senha = PasswordField("Senha", validators=[DataRequired()])
botao_entrar = SubmitField("Entrar")
class Usuarios(db.Model, UserMixin):
__tablename__ = "usuarios"
id = db.Column(db.Integer, primary_key=True)
p_nome = db.Column(db.String(50), nullable=False)
u_nome = db.Column(db.String(50), nullable=False)
login = db.Column(db.String(50), nullable=False)
senha_hash = db.Column(db.String(255), nullable=False)
cargos = db.relationship("CargosUsuarios", backref="usuarios")
def __repr__(self):
return f"<Usuário: {self.id}>"
class Cargos(db.Model):
__tablename__ = "cargos"
id = db.Column(db.Integer, primary_key=True)
nome = db.Column(db.String(50), nullable=False)
descricao = db.Column(db.Text, nullable=False)
usuarios = db.relationship("CargosUsuarios", backref="cargos")
permissoes = db.relationship("PermissoesCargos", backref="cargos")
def __repr__(self):
return f"<Cargo: {self.id}>"
class Permissoes(db.Model):
__tablename__ = "permissoes"
id = db.Column(db.Integer, primary_key=True)
nome = db.Column(db.String(50), nullable=False)
descricao = db.Column(db.Text, nullable=False)
cargos = db.relationship("PermissoesCargos", backref="permissoes")
def __repr__(self):
return f"<Permissão: {self.id}>"
class CargosUsuarios(db.Model):
__tablename__ = "cargos_usuarios"
id = db.Column(db.Integer, primary_key=True)
id_usuario = db.Column(db.Integer, db.ForeignKey("usuarios.id"))
id_cargo = db.Column(db.Integer, db.ForeignKey("cargos.id"))
def __repr__(self):
return f"<Cargos Usuários: {self.id}>"
class PermissoesCargos(db.Model):
__tablename__ = "permissoes_cargos"
id = db.Column(db.Integer, primary_key=True)
id_cargo = db.Column(db.Integer, db.ForeignKey("cargos.id"))
id_permissao = db.Column(db.Integer, db.ForeignKey("permissoes.id"))
def __repr__(self):
return f"<Permissões Cargos: {self.id}>"
#login_manager.user_loader
def load_user(user_id):
return Usuarios.query.get(int(user_id))
def token_required(func):
#wraps(func)
def decorated(*args, **kwargs):
token = session.get("token")
try:
payload = jwt.decode(token, app.config["SECRET_KEY"])
print("Alerta: Token válido!")
except:
print("Alerta: Token inválido!")
#app.route("/", methods=["GET", "POST"])
#app.route("/login", methods=["GET", "POST"])
def render_login():
form = LoginForm()
if form.validate_on_submit():
login = form.login.data
senha = form.senha.data
senha_hash = hashlib.sha256(senha.encode()).hexdigest()
usuario = Usuarios.query.filter_by(login=login).first()
if usuario:
senha_check = usuario.senha_hash
if senha_hash == senha_check:
login_user(usuario)
cargos = []
permissoes = []
for cargo in usuario.cargos:
dados_cargo = Cargos.query.filter_by(id=cargo.id_cargo).first()
cargos.append(dados_cargo.nome)
for permissao in dados_cargo.permissoes:
dados_permissao = Permissoes.query.filter_by(id=permissao.id_permissao).first()
permissoes.append(dados_permissao.nome)
token = jwt.encode({
"usuario": login,
"cargos": cargos,
"permissoes": list(set(permissoes)),
"expiration": str(datetime.utcnow() + timedelta(seconds=120))
},
app.config["SECRET_KEY"]
)
return redirect(url_for("render_graficos"))
return render_template("login.html", form=form)
#app.route("/graficos")
#login_required
def render_graficos():
return render_template("graficos.html")
if __name__ == "__main__":
app.run(debug=True)
Hello I'm struggling with this error since weeks.
In my python/flask app I need to store a pw in a db table user in SQLite with SQLalchemy.
The table seemds to be correctly created when I check sqlite> .schema the column pwd is there.
When I run the app it returns an error saying the column pwd does not exist (see error below).
I tried several times dropping the table, trying in a new db but nothing, I think the table is created correctly but there must be something wrong in the code? Could also be the db that was messed up but I don't think so.
Here I create the table and define the User class, as per official SQLAlchemy documentation
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from sqlalchemy import *
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data-users.sqlite'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer(), primary_key = True, autoincrement=True)
username = db.Column(db.String(64), unique = True)
pwd = db.Column(db.String())
def __repr__(self):
return '<User %r>' % self.username
Here I store the user data in the table
from store_user_db import User, db
db.create_all()
DICP_FTP_DESTINATION_PSW=self.submit_pwd()
user = User(id=001,username="ita_itf",pwd=DICP_FTP_DESTINATION_PSW)
db.session.add(user)
db.session.commit()
This is the error:
sqlalchemy.exc.OperationalError
OperationalError: (sqlite3.OperationalError) table user has no column named pwd
[SQL: INSERT INTO user (id, username, pwd) VALUES (?, ?, ?)]
[parameters: (1, 'ita_itf', <read-only buffer for 0x7efe495709f0, size -1, offset 0 at 0x7.....
I don't have much experience flask and SQlAlchemy, but here is a sample app which is working for me.
The Model definitions are taken from the documentation and added a test model during runtime to see if it is still able to create new tables and it did.
If you have a large app, I'd prefer to use flask-migrate library which can create versioned migrations from your models for creating/modifying your tables.
from datetime import datetime
from flask import Flask, request, flash, url_for, redirect, json
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return '<User %r>' % self.username
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
def __repr__(self):
return '<Category %r>' % self.name
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
body = db.Column(db.Text, nullable=False)
pub_date = db.Column(db.DateTime, nullable=False,
default=datetime.utcnow)
category_id = db.Column(db.Integer, db.ForeignKey('category.id'),
nullable=False)
category = db.relationship('Category',
backref=db.backref('posts', lazy=True))
def __repr__(self):
return '<Post %r>' % self.title
class Test(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
def __repr__(self):
return '<Test %r>' % self.name
def insertAdminUser():
admin = User(username='admin', email='admin#example.com')
db.session.add(admin)
db.session.commit()
#app.route('/insert-admin', methods = ['GET'])
def insertAdmin():
insertAdminUser()
return app.response_class(
response=json.dumps({
"message": "inserted"
}),
mimetype='application/json'
)
if __name__ == '__main__':
db.create_all()
app.run(debug = True)
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"