I'm trying to setup flask-admin model views with SQLAlchemy against 'user' and 'role' models. Instead of a function admin view I'm getting:
ValueError: Invalid model property name <class 'app.models.Role'>.desc
Stack trace:
Traceback (most recent call last):
File "/Users/dbg/Projects/Python/Current/ziff/flaskbase/manage.py", line 18, in <module>
app = create_app(os.getenv('APP_CONFIG') or 'default')
File "/Users/dbg/Projects/Python/Current/ziff/flaskbase/app/__init__.py", line 49, in create_app
admin.add_view(RoleAdmin(Role, db.session))
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/view.py", line 288, in __init__
menu_icon_value=menu_icon_value)
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 570, in __init__
self._refresh_cache()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 640, in _refresh_cache
self._refresh_forms_cache()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 580, in _refresh_forms_cache
self._create_form_class = self.get_create_form()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 856, in get_create_form
return self.get_form()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 848, in get_form
return self.scaffold_form()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/view.py", line 607, in scaffold_form
extra_fields=self.form_extra_fields)
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/form.py", line 427, in get_form
for name, p in properties:
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/form.py", line 422, in <genexpr>
properties = ((x, find(x)) for x in only)
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/form.py", line 419, in find
raise ValueError('Invalid model property name %s.%s' % (model, name))
ValueError: Invalid model property name <class 'app.models.Role'>.desc
I am using a flask application factory approach with blueprints. Here's my application factory.
My __init__.py
file where I try and create the views on line 49:
from flask import Flask
from flask.ext.bootstrap import Bootstrap
from flask.ext.mail import Mail
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security
from flask.ext.admin import Admin
from flask_s3 import FlaskS3
from flask.ext.cdn import CDN
from flask.ext.assets import Environment
from flask.ext.assets import PythonLoader as PythonAssetsLoader
from config import config
# app setup
bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
security = Security()
admin = Admin()
s3 = FlaskS3()
cdn = CDN()
assets_env = Environment()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
app.name = app.config['APP_NAME']
config[config_name].init_app(app)
from .models import user_datastore, User, Role
from .auth.views import RoleAdmin, UserAdmin
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
security.init_app(app, user_datastore)
admin.init_app(app)
s3.init_app(app)
cdn.init_app(app)
assets_env.init_app(app)
# Here's where I'm trying to create the views
admin.add_view(RoleAdmin(Role, db.session))
admin.add_view(UserAdmin(User, db.session))
from . import assets
assets_loader = PythonAssetsLoader(assets)
for name, bundle in assets_loader.load_bundles().iteritems():
assets_env.register(name, bundle)
# attach asset bundles, routes, and custom error pages here
from main import main as main_blueprint
app.register_blueprint(main_blueprint)
import main.assets as main_assets
assets_loader = PythonAssetsLoader(main_assets)
for name, bundle in assets_loader.load_bundles().iteritems():
assets_env.register(name, bundle)
from auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
return app
My ModelView classes:
from flask.ext.admin.contrib.sqla import ModelView
__author__ = 'dbg'
class RoleAdmin(ModelView):
column_display_pk = True
form_columns = ['id', 'desc']
class UserAdmin(ModelView):
column_display_pk = True
form_columns = ['id', 'email', 'active', 'last_login_at', 'login_count', 'roles']
EDIT
Models.py
from app import db
from flask.ext.security import UserMixin, RoleMixin, SQLAlchemyUserDatastore
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):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer(), primary_key=True)
email = db.Column(db.String(256), unique=True)
password = db.Column(db.String(36))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
last_login_at = db.Column(db.DateTime())
current_login_at = db.Column(db.DateTime())
last_login_ip = db.Column(db.String(45))
current_login_ip = db.Column(db.String(45))
login_count = db.Column(db.Integer())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
UPDATE
Found a very helpful write-up here by this good soul. Still stuck. New error.
Traceback (most recent call last):
File "/Users/dbg/Projects/Python/Current/ziff/flaskbase/manage.py", line 18, in <module>
app = create_app(os.getenv('APP_CONFIG') or 'default')
File "/Users/dbg/Projects/Python/Current/ziff/flaskbase/app/__init__.py", line 83, in create_app
admin.add_view(RoleAdmin(RoleAdmin, db.session))
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/view.py", line 288, in __init__
menu_icon_value=menu_icon_value)
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 570, in __init__
self._refresh_cache()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 632, in _refresh_cache
self._list_columns = self.get_list_columns()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/model/base.py", line 708, in get_list_columns
columns = self.scaffold_list_columns()
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/view.py", line 371, in scaffold_list_columns
for p in self._get_model_iterator():
File "/usr/local/share/anaconda/envs/flaskbase27/lib/python2.7/site-packages/Flask_Admin-1.0.9-py2.7.egg/flask_admin/contrib/sqla/view.py", line 310, in _get_model_iterator
return model._sa_class_manager.mapper.iterate_properties
AttributeError: type object 'RoleAdmin' has no attribute '_sa_class_manager'
Flask-Admin is a batteries-included, simple-to-use Flask extension that lets you add admin interfaces to Flask applications. It is inspired by the django-admin package, but implemented in such a way that the developer has total control of the look, feel and functionality of the resulting application.
It offers freedom for you, the designer, to implement your project in a way that suits your particular application. Why Flask-Admin? In a world of micro-services and APIs, Flask-Admin solves the boring problem of building an admin interface on top of an existing data model.
Here is another way using blueprints:
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
db = SQLAlchemy()
admin = Admin(name='my-app', template_mode='bootstrap3')
def create_app():
app = Flask(__name__)
db.init_app(app)
admin.init_app(app)
# Add the admin panel
from app.admin import bp as admin_bp
app.register_blueprint(admin_bp)
return app
# app/admin/__init__.py
from flask import Blueprint
bp = Blueprint('admin_bp', __name__)
from app.admin import routes
# app/admin/routes.py
from flask_admin.contrib.sqla import ModelView
from app import db, admin
from app.models import City
admin.add_view(ModelView(City, db.session))
Well, this is old, but here is how I do it:
# Inside app/auth/__init__.py (auth module includes admin):
#...
from app import db
from flask import Blueprint
from .my_custom_model_views import MyModelView
from ..models import MyModel
#...
auth = Blueprint('auth', __name__)
from . import views
#...
auth.custom_model_views = []
auth.custom_model_views += [MyModelView(MyModel, db.session)]
#...
from . import forms
# Inside app/__init__.py
# ...
admin = Admin(name='Name', ...)
# ...
def create_app(config_name):
# ...
app = Flask(__name__)
# ...
admin.init_app(app)
# And here's the important part
with app.app_context():
from .auth import auth as auth_blueprint
admin.add_views(*auth_blueprint.custom_model_views)
The important part is somehow storing the views you want to add (here, I just attach them to the Blueprint) and then adding them WITH APP CONTEXT. Otherwise, everything goes berserk (without app context, it is possible to add the same model multiple times, resulting in ugly name collision errors during instantiation of the app).
It's worth noting that any views you add here will show up in the flask admin menu as if it were a model view, even if it is some other kind of view. You can fix this by changing the view's is_visible and is_accessible methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With