向项目添加flask-admin时仪表板错误 [英] Wrong dashboard while adding flask-admin to project

查看:59
本文介绍了向项目添加flask-admin时仪表板错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试扩展flask-base项目

我在做什么错了?

按照您的指示,我将create_app更改为:

  def create_app(config_name):app = Flask(__ name__)app.config.from_object(config [config_name])app.config ['SQLALCHEMY_TRACK_MODIFICATIONS'] = False#不使用sqlalchemy事件系统,因此将其禁用#adm = Admin(名称='admin2',端点='/db',url ='/db',template_mode ='bootstrap3',base_template ='admin/db.html')config [config_name] .init_app(app)#设置扩展mail.init_app(app)db.init_app(app)login_manager.init_app(app)csrf.init_app(app)compress.init_app(app)RQ(应用程式)adm = Admin(app,name ='MyAPP')#adm = Admin(endpoint ='adminz',name ='adz',url ='/adminz')adm.add_view(MyView(User,db.session,endpoint ='db')) 

结果为:

register_blueprint中的文件".... flask \ app.py",行946(blueprint,self.blueprints [blueprint.name],blueprint.name)AssertionError:和之间发生了蓝图名称冲突.两者共享相同的名称"admin".动态创建的蓝图需要唯一的名称.

在我添加的create_app末尾:

 #创建应用蓝图从.main导入main作为main_blueprintapp.register_blueprint(main_blueprint)从.account导入帐户作为account_blueprintapp.register_blueprint(account_blueprint,url_prefix ='/account')从.admin导入admin作为admin_blueprint#从.admin导入admin_blueprintapp.register_blueprint(admin_blueprint,url_prefix ='/admin')#app.register_blueprint(admin_blueprint,url_prefix ='/ab')使用app.app_context():m = app.url_map返回应用 

我不确定您想看什么,但是m.rules给出了:

 <规则'/account/manage/change-password'(HEAD,GET,OPTIONS,POST)->account.change_password> ;,<规则'/account/manage/change-email'(HEAD,GET,OPTIONS,POST)->account.change_email_request> ;,<规则'/account/manage/info'(HEAD,GET,OPTIONS,POST)->account.manage> ;,<规则'/account/confirm-account'(HEAD,GET,OPTIONS)->account.confirm_request> ;,<规则'/account/reset-password'(HEAD,GET,OPTIONS,POST)->account.reset_password_request> ;,<规则'/account/unconfirmed'(HEAD,GET,OPTIONS)->account.unconfirmed> ;,<规则'/account/register'(HEAD,GET,OPTIONS,POST)->account.register> ;,<规则'/account/logout'(HEAD,GET,OPTIONS)->account.logout> ;,<规则'/account/manage'(HEAD,GET,OPTIONS,POST)->account.manage> ;,<规则'/account/login'(HEAD,GET,OPTIONS,POST)->account.login> ;,<规则'/admin/_update_editor_contents'(OPTIONS,POST)->admin.update_editor_contents> ;,<规则'/admin/invite-user'(HEAD,GET,OPTIONS,POST)->admin.invite_user> ;,<规则'/admin/new-user'(HEAD,GET,OPTIONS,POST)->admin.new_user> ;,<规则'/admin/users'(HEAD,GET,OPTIONS)->admin.registered_users> ;,<规则'/get_session_job_value'(HEAD,GET,OPTIONS)->main.get_session_job_value> ;,<规则'/cl_confirm_chrome'(HEAD,GET,OPTIONS,POST)->main.cl_confirm_chrome> ;,<规则'/render_png'(HEAD,GET,OPTIONS)->main.render_png> ;,<规则'/selected'(HEAD,GET,OPTIONS)->main.selected> ;,<规则'/cl_dash'(HEAD,GET,OPTIONS,POST)->main.cl_dash> ;,<规则'/about'(HEAD,GET,OPTIONS)->main.about> ;,<规则'/admin/'(HEAD,GET,OPTIONS)->admin.index> ;,<规则'/破折号(HEAD,GET,OPTIONS)->main.dash> ;,<规则'/jobs'(HEAD,GET,OPTIONS)->main.get_jobs> ;,<规则'/'(HEAD,GET,OPTIONS)->main.index> ;,<规则'/帐户/管理/更改电子邮件/<令牌>'(HEAD,GET,OPTIONS,POST)->account.change_email> ;,<规则'/admin/user/< user_id>/更改帐户类型'(HEAD,GET,OPTIONS,POST)->admin.change_account_type> ;,<规则'/admin/user/< user_id>/change-email'(HEAD,GET,OPTIONS,POST)->admin.change_user_email> ;,<规则'/admin/user/< user_id>/_ delete'(HEAD,GET,OPTIONS)->admin.delete_user> ;,<规则'/admin/user/< user_id>/delete'(HEAD,GET,OPTIONS)->admin.delete_user_request> ;,<规则'/admin/user/< user_id>/info'(HEAD,GET,OPTIONS)->admin.user_info> ;,<规则'/account/join-from-invite/< user_id>/<令牌>'(HEAD,GET,OPTIONS,POST)->account.join_from_invite> ;,<规则'/account/confirm-account/<令牌>'(HEAD,GET,OPTIONS)->account.confirm> ;,<规则'/帐户/重置密码/<令牌>'(HEAD,GET,OPTIONS,POST)->account.reset_password> ;,<规则'/admin/static/<文件名>'(HEAD,GET,OPTIONS)->admin.static> ;,<规则'/admin/user/< user_id>'(HEAD,GET,OPTIONS)->admin.user_info> ;,<规则'/results/< job_key>'(HEAD,GET,OPTIONS)->main.get_results> ;,<规则'/static/<文件名>'(HEAD,GET,OPTIONS)->静态> 

我不得不说这是一个令人难以置信的答案!你真的教了我很多.我已按照您的指示将网址替换为上述规则.我10天前的最初计划只是使用基本的flask-admin CRUD功能.我对db.html模板不感兴趣(这只是我尝试过的事情).

无论如何尝试更改管理蓝图的名称(您的数字1).在将app/admin/init.py更改为:

之前,我曾尝试过此操作从烧瓶导入

 蓝图admin =蓝图('admin_blueprint',__name__)从 .导入视图#noqa 

现在我打开

  http://127.0.0.1:5000/adminz/ 

我收到404错误

最终

> https://chat.stackoverflow.com/users/5819113/diego-quintana ,他解释了创建蓝图的flask-admin与flask-base admin蓝图之间存在冲突.通过更改蓝图的名称和flask-base项目的静态文件文件夹.Flask-admin可以正常工作而不会被覆盖.请参阅 https://github.com/kc1/flask-base

解决方案

您应该初始化 Admin 并将 views blueprints 注册在 create_app .检查它是否适合您.

 #应用程序工厂def create_app(config_name):#配置当前应用app = Flask(__ name__)app.config.from_object(config [config_name])config [config_name] .init_app(app)#包装带有扩展程序的应用程序...#admin.init_app(app)不起作用,flask-admin#应该在create_app()中实例化#参见https://github.com/flask-admin/flask-admin/issues/910#issuecomment-115003492#了解详情管理员=管理员(应用程序,名称='MyAPP')...#导入模型从.models.user导入用户#这里有更多进口#导入要在管理面板中使用的flask-admin视图从.admin.views导入MyView#注册管理员查看表单admin.add_view(MyView(name ='MyCustomView',端点='db'))#注册蓝图#...#实现应用程序工厂模式返回应用 

我相信正在发生的事情

  • 回购中的应用程序已经存在一个名为 admin 的蓝图,位于/admin
  • 您想在应用程序中实现 flask-admin ,但与现有蓝图冲突

您可以通过做两件事来实现:

  1. 将仓库中的当前 blueprint 名称更改为与 admin 不同的名称,因为 flask-admin 与之冲突.(从github问题中读取,似乎 admin.static 有很多硬编码的内部组件,这使得更改当前的 admin 蓝图更加容易.

蓝图的解剖结构有点像

 #app/myblueprint/__ init__.py从烧瓶进口蓝图#随机蓝图myblueprint =蓝图(name ='mycustomblueprint',import_name = __ name __,#文件名static_folder ='static',#一个位于app/myblueprint/static中的文件夹template_folder ='templates',#app/myblueprint/templates内的一个文件夹static_url_path ='/static',#这是mycustomblueprint.static将指向的内容,如果名称是admin,它将是admin.static,从而与flask-admin冲突url_prefix ='/myblueprintprefix',#这将附加到您的蓝图中的每个视图中,即视图'/foo'将在您的url映射中转换为'/myblueprintprefix/foo'subdomain = None,url_defaults =无,root_path =无)从 .导入视图#将视图导入app/myblueprint/views.py 

然后,将其作为

导入到 create_app 内来自.myblueprint的

 导入myblueprint作为my_blueprintapp.register_blueprint(my_blueprint)#注意,我在蓝图"定义中定义了url_prefix.您可以在注册时完成,这取决于您 

tl; dr:更改 admin 蓝图,因为它与 flask-admin

冲突

  1. flask-admin 基于视图工作,并且生成管理视图的模式是通过导入并传递一个 url 参数来获取附加到/admin 端点( flask-admin 所在的位置).在这种情况下,您可以想到两种口味(更多,但出于示例考虑,还可以)
    • ModelView ,可用于创建自定义的CRUD视图,并同时使用 model db.session 对象.
    • BaseView ,可用于在 flask-admin 使用的 admin 蓝图内扩展通用视图.

这意味着,如果要在 flask-admin 视图中呈现自己的 db.html 文件,则必须执行以下操作:

 #app/modelviews/mycustomviews.py从flask_admin导入BaseView,公开类DBView(BaseView):#注意我正在使用BaseView而不是ModelView@暴露('/')def索引(自己):return self.render('modelviews/db.html')#此文件应该存在于app/templates/modelviews/db.html中 

create_app

 #注册管理员视图表格从.modelviews导入DBViewadmin.add_view(DBView(name ='MyCustomView',endpoint ='db'))#这将以MyCustomView的形式显示在您的Flask-admin主视图中,并将位于{host}/admin/db中 

您还可以在所拥有的上下文中检入flask应用程序的 url_map 参数.您不需要在 create_app

中使用此位

 和app.app_context():m = app.url_map 

我提到它是因为它可以帮助您在python repl 中调试视图.导入您的应用,然后按照我提供的要旨进行操作. url_map 应该返回类似< Rules>

列表的内容

  [<规则'/admin/'(选项,HEAD,GET)->admin.index> ;,<规则'/admin/db'(OPTIONS,HEAD,GET)->dbview.index>] 

通过这种方式,您可以确认视图位于应有的位置.希望这会有所帮助.

I'm trying to extend the flask-base project https://github.com/hack4impact/flask-base/tree/master/app. This uses the the application factory pattern in app/init.py and blueprints.

In the app/init.py I have:

import os
from flask import Flask
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_assets import Environment
from flask_wtf import CsrfProtect
from flask_compress import Compress
from flask_rq import RQ
from flask_admin import Admin, BaseView, expose
from flask_admin.contrib.sqla import ModelView
# from app.models import User


from config import config
from .assets import app_css, app_js, vendor_css, vendor_js




basedir = os.path.abspath(os.path.dirname(__file__))

mail = Mail()
db = SQLAlchemy()
csrf = CsrfProtect()
compress = Compress()


# Set up Flask-Login
login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'account.login'

from app.models import User


def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    # not using sqlalchemy event system, hence disabling it


    with app.app_context():
        m =app.url_map

    config[config_name].init_app(app)

    # Set up extensions
    mail.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    csrf.init_app(app)
    compress.init_app(app)
    RQ(app)
    # adm = Admin(app, name='MyAPP')
    adm = Admin(endpoint='adminz', name='adz', url='/adminz')



   ......

    # Create app blueprints
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    from .account import account as account_blueprint
    app.register_blueprint(account_blueprint, url_prefix='/account')

    from .admin import admin as admin_blueprint
    # from .admin import admin_blueprint
    app.register_blueprint(admin_blueprint, url_prefix='/admin')

    return app

templates/admin/db.html:

<p>Hello world</p>

To the admin views (https://github.com/hack4impact/flask-base/blob/master/app/admin/views.py) I've added :

from flask_admin import Admin, BaseView, expose
from flask_admin.contrib.sqla import ModelView
from app import adm as adm, db

class MyView(ModelView):
    @expose('/')
    def db(self):
        return self.render('admin/db.html')


# admin management setup
@main.route('/db')
def db():
    adm.add_view(MyView(User, db.session))

I'm getting the admin dashboard not the flask-admin basic view when I open:

 127.0.0.1:5000/db

What am I doing wrong?

EDIT:

following your directions I changed create_app to start with:

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    # not using sqlalchemy event system, hence disabling it
    # adm = Admin(name='admin2', endpoint='/db', url='/db', template_mode='bootstrap3',base_template='admin/db.html')


    config[config_name].init_app(app)

    # Set up extensions
    mail.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    csrf.init_app(app)
    compress.init_app(app)
    RQ(app)
    adm = Admin(app, name='MyAPP')
    # adm = Admin(endpoint='adminz', name='adz', url='/adminz')
    adm.add_view(MyView(User, db.session, endpoint='db'))

This results in :

File "....flask\app.py", line 946, in register_blueprint (blueprint, self.blueprints[blueprint.name], blueprint.name) AssertionError: A blueprint's name collision occurred between and . Both share the same name "admin". Blueprints that are created on the fly need unique names.

EDIT2:

to the end of create_app I've added:

# Create app blueprints
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)

from .account import account as account_blueprint
app.register_blueprint(account_blueprint, url_prefix='/account')

from .admin import admin as admin_blueprint
# from .admin import admin_blueprint
app.register_blueprint(admin_blueprint, url_prefix='/admin')
# app.register_blueprint(admin_blueprint, url_prefix='/ab')

with app.app_context():
    m =app.url_map

return app

I'm not sure what you want to see but m.rules gives:

 <Rule '/account/manage/change-password' (HEAD, GET, OPTIONS, POST) -> account.change_password>,
 <Rule '/account/manage/change-email' (HEAD, GET, OPTIONS, POST) -> account.change_email_request>,
 <Rule '/account/manage/info' (HEAD, GET, OPTIONS, POST) -> account.manage>,
 <Rule '/account/confirm-account' (HEAD, GET, OPTIONS) -> account.confirm_request>,
 <Rule '/account/reset-password' (HEAD, GET, OPTIONS, POST) -> account.reset_password_request>,
 <Rule '/account/unconfirmed' (HEAD, GET, OPTIONS) -> account.unconfirmed>,
 <Rule '/account/register' (HEAD, GET, OPTIONS, POST) -> account.register>,
 <Rule '/account/logout' (HEAD, GET, OPTIONS) -> account.logout>,
 <Rule '/account/manage' (HEAD, GET, OPTIONS, POST) -> account.manage>,
 <Rule '/account/login' (HEAD, GET, OPTIONS, POST) -> account.login>,
 <Rule '/admin/_update_editor_contents' (OPTIONS, POST) -> admin.update_editor_contents>,
 <Rule '/admin/invite-user' (HEAD, GET, OPTIONS, POST) -> admin.invite_user>,
 <Rule '/admin/new-user' (HEAD, GET, OPTIONS, POST) -> admin.new_user>,
 <Rule '/admin/users' (HEAD, GET, OPTIONS) -> admin.registered_users>,
 <Rule '/get_session_job_value' (HEAD, GET, OPTIONS) -> main.get_session_job_value>,
 <Rule '/cl_confirm_chrome' (HEAD, GET, OPTIONS, POST) -> main.cl_confirm_chrome>,
 <Rule '/render_png' (HEAD, GET, OPTIONS) -> main.render_png>,
 <Rule '/selected' (HEAD, GET, OPTIONS) -> main.selected>,
 <Rule '/cl_dash' (HEAD, GET, OPTIONS, POST) -> main.cl_dash>,
 <Rule '/about' (HEAD, GET, OPTIONS) -> main.about>,
 <Rule '/admin/' (HEAD, GET, OPTIONS) -> admin.index>,
 <Rule '/dash' (HEAD, GET, OPTIONS) -> main.dash>,
 <Rule '/jobs' (HEAD, GET, OPTIONS) -> main.get_jobs>,
 <Rule '/' (HEAD, GET, OPTIONS) -> main.index>,
 <Rule '/account/manage/change-email/<token>' (HEAD, GET, OPTIONS, POST) -> account.change_email>,
 <Rule '/admin/user/<user_id>/change-account-type' (HEAD, GET, OPTIONS, POST) -> admin.change_account_type>,
 <Rule '/admin/user/<user_id>/change-email' (HEAD, GET, OPTIONS, POST) -> admin.change_user_email>,
 <Rule '/admin/user/<user_id>/_delete' (HEAD, GET, OPTIONS) -> admin.delete_user>,
 <Rule '/admin/user/<user_id>/delete' (HEAD, GET, OPTIONS) -> admin.delete_user_request>,
 <Rule '/admin/user/<user_id>/info' (HEAD, GET, OPTIONS) -> admin.user_info>,
 <Rule '/account/join-from-invite/<user_id>/<token>' (HEAD, GET, OPTIONS, POST) -> account.join_from_invite>,
 <Rule '/account/confirm-account/<token>' (HEAD, GET, OPTIONS) -> account.confirm>,
 <Rule '/account/reset-password/<token>' (HEAD, GET, OPTIONS, POST) -> account.reset_password>,
 <Rule '/admin/static/<filename>' (HEAD, GET, OPTIONS) -> admin.static>,
 <Rule '/admin/user/<user_id>' (HEAD, GET, OPTIONS) -> admin.user_info>,
 <Rule '/results/<job_key>' (HEAD, GET, OPTIONS) -> main.get_results>,
 <Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>

EDIT 3:

I have to say that is an incredible answer! You have really taught me a lot. I have replaced the urls with the rules above following your directions. My original plan 10 days ago was just to use the basic flask-admin CRUD functionality. I'm not interested in the db.html template (its just something I tried).

anyway trying to change the name of the admin blueprint ( your number 1). I had tried this before changing app/admin/init.py to :

from flask import Blueprint
admin = Blueprint('admin_blueprint', __name__)
from . import views  # noqa

Now when I open

http://127.0.0.1:5000/adminz/

I get a 404 error

FINAL EDIT:

The problem was solved by https://chat.stackoverflow.com/users/5819113/diego-quintana who explained that there was a conflict between flask-admin which creates a blueprint and the flask-base admin blueprint. By changing both the name of the blueprint and the static file folder of the flask-base project. Flask-admin could work without being overridden. Please see https://github.com/kc1/flask-base

解决方案

You should be initializing Admin and registering views and blueprints inside create_app. Check if this works for you.

# app factory
def create_app(config_name):

    # configure current app
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    # wrap app with extensions
   ...

    # admin.init_app(app) does not work and flask-admin
    # should be instantiated inside create_app()
    # see https://github.com/flask-admin/flask-admin/issues/910#issuecomment-115003492
    # for details
    admin = Admin(app, name='MyAPP')

    ...

    # import models 
    from .models.user import User
    # more imports happening here

    # import flask-admin views to be used in the admin panel
    from .admin.views import MyView


    # register admin view forms
    admin.add_view(MyView(name='MyCustomView', endpoint='db'))

    # register blueprints
    # ...

    # implementation of the app factory pattern
    return app

EDIT:

What I believe is happening is that

  • The app in the repo has already a blueprint named admin living in /admin
  • You want to implement flask-admin in the app, but it clashes with the existing blueprint

You can achieve this doing two things:

  1. Change the current blueprint name in the repo to something different from admin, since flask-admin clashes with it. (Reading from your github issue it seems the are a lot of hardcoded internals for admin.static, which makes changing the current admin blueprint easier.

the anatomy of a Blueprint is kinda like this

# app/myblueprint/__init__.py
from flask import Blueprint

# a random blueprint
myblueprint = Blueprint(name='mycustomblueprint', 
                         import_name=__name__, # name of the file
                         static_folder='static', # a folder inside app/myblueprint/static
                         template_folder='templates', # a folder inside app/myblueprint/templates
                         static_url_path='/static', # this is what mycustomblueprint.static will point to, and if the name is admin it will be admin.static, thus colliding with flask-admin
                         url_prefix='/myblueprintprefix', # this will be appended to each view inside your blueprint, i.e. a view '/foo' will get converted into '/myblueprintprefix/foo' in your url mappings
                         subdomain=None,
                         url_defaults=None,
                         root_path=None)

from . import views # import the views inside app/myblueprint/views.py

then, you import it inside create_app as

from .myblueprint import myblueprint as my_blueprint
app.register_blueprint(my_blueprint) # notice I've defined url_prefix in the Blueprint definition. You can do it at registration time, it's up to you

tl;dr: change the admin blueprint since it's clashing with flask-admin

  1. flask-admin works based in views, and the pattern to generate admin views is by importing them and passing an url parameter that gets appended to the /admin endpoint (where flask-admin lives). In this case, you can think of two flavours (more but for the sake of the example it's okay)
    • ModelView, which you use to create custom CRUD views and takes both a model and a db.session object.
    • BaseView which you use to extend a generic view inside the admin blueprint used by flask-admin.

This means, if you want to render your own db.html file inside the flask-admin views, you have to do:

# app/modelviews/mycustomviews.py
from flask_admin import BaseView, expose

class DBView(BaseView): # notice I'm using BaseView and not ModelView
    @expose('/')
    def index(self):
        return self.render('modelviews/db.html') # this file should live in app/templates/modelviews/db.html

and inside create_app

# register admin view forms
from .modelviews import DBView
admin.add_view(DBView(name='MyCustomView', endpoint='db')) # this will show up in your `flask-admin` main view as MyCustomView, and it will live in {host}/admin/db

You can also check in your url_map parameter of the flask app in context that you have. You don't need this bit in your create_app

with app.app_context():
m =app.url_map

I mentioned it because it could help you debug your views inside the python repl. Import your app, and follow the gist I've provided. The url_map should return something like a list of <Rules>

 [<Rule '/admin/' (OPTIONS, HEAD, GET) -> admin.index>,
 <Rule '/admin/db' (OPTIONS, HEAD, GET) -> dbview.index>]

This way you can confirm that your view lives where it should. Hope this helps.

这篇关于向项目添加flask-admin时仪表板错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆