I created my ModelView in flask-admin and want to give role choices to user such that only admin can create user with role manager,admin or user. And user shouldn't have choice to give admin privilidges or as such. I am trying this code but it's giving me:
AttributeError: 'NoneType' object has no attribute 'is_authenticated'
class UserView(ModelView):
column_exclude_list = ['logs', 'password_hash',]
form_excluded_columns = ['logs']
can_edit = True
if login.current_user or current_user.is_authenticated:
if login.current_user.role == 'a':
form_choices = {
'role': [ ('a', 'Admin'), ('m', 'Manager'), ('u', 'User') ]
}
if login.current_user.role == 'm':
form_choices = {
'role': [
('m', 'Manager'),
('u', 'User')
]
}
Any help would be highly appreciated.
Evaluating current_user
always returns a NoneType
unless it is within a Flask application context. Do something like the following:
def get_user_roles():
_roles = []
if current_user and current_user.is_authenticated:
if current_user.role == 'a':
_roles = [('a', 'Admin'), ('m', 'Manager'), ('u', 'User')]
elif login.current_user.role == 'm':
_roles = [('m', 'Manager'), ('u', 'User')]
return _roles
class UserView(ModelView):
form_choices = {
'role' : get_user_roles
}
Single file example. If you run this without logging in you will see only the "User" role in the role choices:
requirements.txt
Babel==2.11.0
blinker==1.5
click==8.1.3
colorama==0.4.6
dnspython==2.2.1
email-validator==1.3.0
Flask==2.2.2
Flask-Admin==1.6.0
Flask-BabelEx==0.9.4
Flask-Login==0.6.2
Flask-Mail==0.9.1
Flask-Principal==0.4.0
Flask-SQLAlchemy==3.0.2
Flask-WTF==1.0.1
greenlet==2.0.1
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
passlib==1.7.4
pytz==2022.6
speaklater==1.3
SQLAlchemy==1.4.44
Werkzeug==2.2.2
WTForms==3.0.1
app.py
import os
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
import click
from flask import Flask, current_app
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_login import current_user, UserMixin, LoginManager
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
login_manager = LoginManager()
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Unicode(length=255), nullable=False)
last_name = db.Column(db.Unicode(length=255), nullable=False, index=True)
# Identification Data: email & password
email = db.Column(db.Unicode(length=254), nullable=False, unique=True)
password = db.Column(db.Unicode(length=255), nullable=False)
active = db.Column(db.Boolean(), default=False)
role = db.Column(db.Unicode(length=255), nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'database.db')
db.init_app(app)
login_manager.init_app(app)
@app.cli.command('create-database', short_help='Create sample database')
def create_database():
"""
Create database
"""
db.drop_all()
db.create_all()
users = [
{
'email': 'paul@example.net',
'first_name': 'Paul',
'last_name': 'Cunningham',
'password': generate_password_hash('pa$$word'),
'active': True,
'role': 'a',
},
{
'email': 'jane@example.net',
'first_name': 'Jane',
'last_name': 'Smith',
'password': generate_password_hash('pa$$word'),
'active': True,
'role': 'm'
},
]
for user in users:
_user_db = User(**user)
db.session.add(_user_db)
db.session.commit()
@app.route('/')
def index(): # put application's code here
return '<a href="/admin/">Click me to get to Admin!</a>'
admin = Admin(app, template_mode="bootstrap3")
def get_user_roles():
# default role is a user
_roles = [('u', 'User')]
if current_user and current_user.is_authenticated:
if current_user.has_role('a'):
print('Current user is an admin')
_roles = [('a', 'Admin'), ('m', 'Manager'), ('u', 'User')]
elif current_user.has_role('m'):
print('Current user is a manager')
_roles = [('m', 'Manager'), ('u', 'User')]
print(f"Roles assigned to role choices: {_roles}")
return _roles
class UserView(ModelView):
column_list = ('first_name', 'last_name', 'email', 'role')
form_columns = column_list
form_choices = {
'role': get_user_roles
}
admin.add_view(UserView(User, db.session))
if __name__ == '__main__':
app.run()
Run the following command to initialize an SQLite DB.
flask create-database