【问题标题】:How do I properly set up flask-admin views with using an application factory?如何使用应用程序工厂正确设置烧瓶管理员视图?
【发布时间】:2015-04-15 00:48:15
【问题描述】:

我正在尝试针对“用户”和“角色”模型设置 flask-admin model views with SQLAlchemy。我得到的不是功能管理视图:

ValueError: Invalid model property name <class 'app.models.Role'>.desc

堆栈跟踪:

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

我正在使用带有蓝图的烧瓶应用程序工厂方法。这是我的应用程序工厂。

我的__init__.py 文件,我尝试在第 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

我的模型视图类:

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']

编辑

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)

更新

通过good soul 发现了一篇非常有用的文章here。还是卡住了。新错误。

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'

【问题讨论】:

  • 查看您的跟踪信息,您的 RoleAdmin 中的“desc”似乎是导致问题的原因?你在模型/表中有那一列吗?
  • 请显示角色模型的定义。
  • @xbb 我有一个描述列,可以在我刚刚添加的 models.py 脚本中看到
  • 我刚刚找到this 并且会尝试一下。
  • @davidbgonzalez 你不应该放description 而不是desc 吗?抱歉不太熟悉。

标签: python flask flask-sqlalchemy flask-admin


【解决方案1】:

这是使用蓝图的另一种方式:

# 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))

【讨论】:

    【解决方案2】:

    嗯,这是旧的,但这是我的做法:

    # 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)
    

    重要的部分是以某种方式存储您想要添加的视图(这里,我只是将它们附加到蓝图),然后将它们添加到应用程序上下文中。否则,一切都会变得疯狂(没有应用上下文,可能会多次添加相同的模型,从而导致在应用实例化过程中出现丑陋的名称冲突错误)。

    值得注意的是,您在此处添加的任何视图都会像模型视图一样显示在烧瓶管理菜单中,即使它是其他类型的视图。您可以通过更改视图的 is_visible 和 is_accessible 方法来解决此问题。

    【讨论】:

    • 关于不添加应用上下文以避免名称冲突(而是使用 init_app)帮助我解决了今天的一个主要 Flask 管理问题,所以谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-04-15
    • 2015-07-04
    • 1970-01-01
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多