【问题标题】:Flask-Admin Blueprint creation during Testing测试期间创建 Flask-Admin 蓝图
【发布时间】:2013-08-01 19:22:04
【问题描述】:

我在测试我的应用时遇到了 Flask-Admin 创建蓝图的问题。

这是我的视图类(使用 SQLAlchemy)

##
# All views that only admins are allowed to see should inherit from this class.
#
class AuthView(ModelView):
    def is_accessible(self):
        return current_user.is_admin()

class UserView(AuthView):
    column_list = ('name', 'email', 'role_code')

这是我初始化视图的方式:

# flask-admin
admin.add_view(UserView(User, db.session))
admin.init_app(app)

但是,当我尝试运行多个测试时(故障总是发生在第二个测试和随后的所有其他测试中),我总是收到以下错误消息:

======================================================================
ERROR: test_send_email (tests.test_views.TestUser)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/lib/python2.7/site-packages/nose/case.py", line 133, in run
    self.runTest(result)
  File "/lib/python2.7/site-packages/nose/case.py", line 151, in runTest
    test(result)
  File "/lib/python2.7/site-packages/flask_testing.py", line 72, in __call__
    self._pre_setup()
  File "/lib/python2.7/site-packages/flask_testing.py", line 80, in _pre_setup
    self.app = self.create_app()
  File "/tests/test_init.py", line 27, in create_app
    app = create_app(TestConfig)
  File "/fbone/app.py", line 41, in create_app
    configure_extensions(app)
  File "/fbone/app.py", line 98, in configure_extensions
    admin.add_view(UserView(User, db.session))
  File "/lib/python2.7/site-packages/flask_admin/base.py", line 484, in add_view
    self.app.register_blueprint(view.create_blueprint(self))
  File "/lib/python2.7/site-packages/flask/app.py", line 62, in wrapper_func
    return f(self, *args, **kwargs)
  File "/lib/python2.7/site-packages/flask/app.py", line 885, in register_blueprint
    (blueprint, self.blueprints[blueprint.name], blueprint.name)
AssertionError: A blueprint's name collision occurred between <flask.blueprints.Blueprint object at 0x110576910> and <flask.blueprints.Blueprint object at 0x1103bd3d0>.  Both share the same name "userview".  Blueprints that are created on the fly need unique names.

奇怪的是,这只发生在第二次测试中,而在我运行应用程序时从来没有。

当我调试测试时,它第一次完全符合我的预期,并在 init_app(app) 之后将蓝图添加到应用程序中。但是第二次在到达 add_view 步骤时该过程立即停止(我认为这很奇怪,因为蓝图已在 init_app(app) 调用中注册?)

【问题讨论】:

  • 当您说“第一次”时,您是指在您的第一次测试中,还是说您的单元测试已完成并且您正在再次运行整个测试套件。
  • 我的意思是第一次测试
  • 确保为每个测试在应用程序工厂中创建 Admin 类的新实例。看起来您在每次测试运行时都在为现有的 Admin 类实例添加视图。

标签: python flask-sqlalchemy flask flask-admin


【解决方案1】:

我在使用 Flask-Admin 和使用 pytest 进行测试时也发生了同样的事情。通过将管理实例的创建移到应用工厂中,我能够在不为我的测试创建拆卸函数的情况下修复它。

之前:

# extensions.py
from flask.ext.admin import Admin
admin = Admin()

# __init__.py
from .extensions import admin

def create_app():
    app = Flask('flask_app')

    admin.add_view(sqla.ModelView(models.User, db.session))
    admin.init_app(app)

    return app

之后:

# __init__.py
from flask.ext.admin import Admin

def create_app():
    app = Flask('flask_app')

    admin = Admin()

    admin.add_view(sqla.ModelView(models.User, db.session))    
    admin.init_app(app)

    return app

因为 pytest 每次不再尝试在全局管理实例上注册多个视图时都会运行应用程序工厂。这与典型的 Flask 扩展用法不一致,但它可以工作,并且可以防止您的应用工厂在 Flask-Admin 视图上绊倒。

【讨论】:

    【解决方案2】:

    我必须将以下内容添加到我的测试用例拆解中。它清理了在测试设置中添加到管理扩展的视图

    from flask.ext.testing import TestCase
    from flask.ext.admin import BaseView
    
    # My application wide instance of the Admin manager
    from myapp.extensions import admin 
    
    
    class TestView(BaseView):
        ...
    
    
    class MyTestCase(TestCase):
        def setUp(self):
            admin.add_view(TestView())
    
        def tearDown(self):
           admin._views.pop(-1)
           admin._menu.pop(-1)
    

    这当然是个小技巧,但是当我遇到这个问题时它就完成了工作。

    【讨论】:

      【解决方案3】:

      以防万一这对任何人都有帮助, 另一种处理方法是:

      class MyTestCase(TestCase):
          def setUp(self):
              admin._views = []
      

      这样您就不必在工厂内设置 Admin() 初始化。好像更适合我。

      【讨论】:

        【解决方案4】:

        以这种方式解决。仅供参考。

        #YourApp/init.py
        from flask import Flask
        from flask_sqlalchemy import SQLAlchemy
        from flask_admin import Admin
        
        db = SQLAlchemy()
        admin = Admin(name='TuozhanOA', template_mode='bootstrap3')
        def create_app(config_class=Config):
            app = Flask(name)
            app.config.from_object(Config)
            db.init_app(app)
            admin.init_app(app)
            from YourApp.main.routes import main
            app.register_blueprint(main)
            from YourApp.adminbp.routes import adminbp, user_datastore
            app.register_blueprint(adminbp)
            security = Security(app, user_datastore)
            return app
        
        #YourApp/adminbp/routes.py
        from flask import render_template, Blueprint
        from YourApp.models import User, Role
        from YourApp import db, admin
        from flask_admin.contrib.sqla import ModelView
        from wtforms.fields import PasswordField
        from flask_admin.contrib.fileadmin import FileAdmin
        import os.path as op
        
        from flask_security import current_user, login_required, RoleMixin, Security, 
        SQLAlchemyUserDatastore, UserMixin, utils
        
        adminbp = Blueprint('adminbp', name)
        admin.add_view(ModelView(User, db.session, category="Team"))
        admin.add_view(ModelView(Role, db.session, category="Team"))
        
        path = op.join(op.dirname(file), 'tuozhan')
        admin.add_view(FileAdmin(path, '/static/tuozhan/', name='File Explore'))
        

        【讨论】:

          猜你喜欢
          • 2013-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-12
          • 2016-01-24
          • 2012-09-14
          • 2018-10-17
          • 1970-01-01
          相关资源
          最近更新 更多