胖蔡说技术
随便扯扯

Flask 中使用flask-admin实现数据模型绑定视图

更多Flask阅读指南:

Flask基础学习

Flask 扩展

Flask 进阶

Flask中提供了flask-admin用来解决在现有数据模型之上构建管理界面的问题。我们只需要写很少的代码,它就可以通过友好的界面来管理web服务的数据。

Flask-Admin 背后的基本概念是,它允许您通过将各个视图分组到类中来构建复杂的界面:您在前端看到的每个网页都代表一个类上的一个方法,该方法已明确添加到界面中。

这些视图类在绑定到特定数据库模型时特别有用,因为它们允许您将所有常用的创建、读取、更新、删除 (CRUD) 视图逻辑组合到每个模型的单个、独立的类中。

初始化

首先初始化一个空的管理界面:

from flask import Flask
from flask_admin import Admin

app = Flask(__name__)

# 设置可选的 bootswatch 主题
app.config['FLASK_ADMIN_SWATCH'] = 'cerulean' 

admin = Admin(app, name='microblog', template_mode='bootstrap3')
# 在此处添加管理视图

app.run()

这里,name template_mode 参数都是可选的。或者,您可以使用 init_app() 方法。

添加模型视图

模型视图允许您添加一组专用的管理页面来管理数据库中的任何模型。通过创建 ModelView 类的实例来完成此操作,您可以从 Flask-Admin 的内置 ORM 后端之一导入该实例。一个示例是 SQLAlchemy 后端,您可以按如下方式使用它:

from flask_admin.contrib.sqla import ModelView
from flask_sqlalchemy import SQLAlchemy
from flask import Flask

app = Flask(__name___)

# 增加数据库模型视图
class Users(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    created_at = db.Column(db.TIMESTAMP)
    updated_at = db.Column(db.TIMESTAMP)
    username = db.Column(db.String(50))
    email = db.Column(db.String(50))
    nickname = db.Column(db.String(100))
    avatar = db.Column(db.String(200))
    password_hash = db.Column(db.String(200))
    status = db.Column(db.Integer)

def initApp():
    db = SQLAlchemy()
    db.init_app(app)
    admin = Admin(app, name='microblog', template_mode='bootstrap3')
    admin.add_view(ModelView(User, db.session))

if __name__ == '__main__':
    app.run()

开箱即用,这为您的模型提供了一组功能齐全的 CRUD 视图:

  • 列表视图,支持搜索、排序、过滤和删除记录。
  • 用于添加新记录的创建视图。
  • 用于更新现有记录的编辑视图。
  • 可选的只读详细信息视图。


有许多选项可用于自定义这些内置视图的显示和功能。有关更多详细信息,请参阅自定义内置视图。有关可用的其他 ORM 后端的更多详细信息,请参阅使用不同的数据库后端。


将内容添加到索引页

当您访问 http://localhost:5000/admin/ 时,您会注意到的第一件事是它只是一个带有导航菜单的空白页面。要向此页面添加一些内容,请将以下文本保存为项目模板目录中的 admin/index.html

{% extends 'admin/master.html' %}

{% block body %}
  <p>Hello world</p>
{% endblock %}


这将覆盖默认索引模板,但仍会为您提供内置导航菜单。因此,现在您可以向索引页添加任何内容,同时保持一致的用户体验。

授权与权限


为您的应用程序设置管理界面时,您首先要解决的问题之一是如何将不需要的用户拒之门外。使用 Flask-Admin 有几种不同的方法可以解决这个问题。

HTTP 基本认证

不幸的是,没有简单的方法可以将 HTTP Basic Auth 仅应用于您的管理界面。

最简单的身份验证形式是 HTTP Basic Auth。它不会干扰您的数据库模型,也不需要您编写任何新的视图逻辑或模板代码。因此,当您部署仍在开发中的东西时,它非常适合在您希望全世界看到它之前。

查看 Flask-BasicAuth,了解将整个应用程序置于 HTTP Basic Auth 之后是多么容易。

自定义访问规则

对于更灵活的解决方案,Flask-Admin 允许您通过简单地覆盖 is_accessible 方法来定义每个管理视图类的访问控制规则。如何实现逻辑取决于您,但如果您要使用像 Flask-Login 这样的低级库,那么限制访问可以像这样简单:

class MicroBlogModelView(sqla.ModelView):

    def is_accessible(self):
        return login.current_user.is_authenticated

    def inaccessible_callback(self, name, **kwargs):
        # 如果用户没有访问权限,则重定向到登录页面
        return redirect(url_for('login', next=request.url))

在导航菜单中,特定用户无法访问的组件将不会为该用户显示。有关将 Flask-Login Flask-Admin 一起使用的示例,请查看 https://github.com/flask-admin/Flask-Admin/tree/master/examples/auth-flask-login

主要缺点是您仍然需要自己实现所有相关的登录、注册和帐户管理视图。

使用Flask-Security

如果你想要一个更完善的解决方案,你可以使用 Flask-Security,这是一个更高级别的库。它带有许多内置视图,用于执行用户注册、登录、电子邮件地址确认、密码重置等常见操作。


唯一复杂的一点是让内置的 Flask-Security 视图与 Flask-Admin 模板平滑集成,以创建一致的用户体验。为此,您需要覆盖内置的 Flask-Security 模板,并通过将以下内容添加到每个文件的顶部来让它们扩展 Flask-Admin 基本模板:

{% extends 'admin/master.html' %}

现在,您需要为 Flask-Admin 模板手动传递一些上下文变量,以便在从 Flask-Security 视图调用它们时正确呈现它们。定义一个 security_context_processor 函数将为您解决这个问题:

def security_context_processor():
    return dict(
        admin_base_template=admin.base_template,
        admin_view=admin.index_view,
        h=admin_helpers,
    )

有关使用 Flask-Security Flask-Admin 的工作示例,请查看 https://github.com/flask-admin/Flask-Admin/tree/master/examples/auth

该示例仅使用内置的注册和登录视图,但您可以采用相同的方法来包括其他视图,如忘记密码、发送确认等。

自定义内置视图

ModelView 继承时,可以为许多配置参数指定值。使用这些来自定义视图以适合您的特定模型:

from flask_admin.contrib.sqla import ModelView

# 增加数据库模型视图
class Users(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    created_at = db.Column(db.TIMESTAMP)
    updated_at = db.Column(db.TIMESTAMP)
    username = db.Column(db.String(50))
    email = db.Column(db.String(50))
    nickname = db.Column(db.String(100))
    avatar = db.Column(db.String(200))
    password_hash = db.Column(db.String(200))
    status = db.Column(db.Integer)

class MicroBlogModelView(ModelView):
    can_delete = False  # 禁用模型删除
    page_size = 50  # 要在列表视图中显示的条目数

admin.add_view(MicroBlogModelView(User, db.session))

或者,以几乎相同的方式,您可以一次为单个模型指定选项:

class UserView(ModelView):
        can_delete = False  # 禁用模型删除

class PostView(ModelView):
        page_size = 50  # 要在列表视图中显示的条目数

admin.add_view(UserView(User, db.session))
admin.add_view(PostView(Post, db.session))


模型视图配置属性

有关已定义属性的完整列表,请查看 BaseModelView() 的 API 文档。以下是一些最常用的属性:

要禁用某些 CRUD 操作,请设置以下任一布尔参数:

can_create = False
can_edit = False
can_delete = False


如果您的模型有太多数据无法在列表视图中显示,您可以通过设置添加只读详细信息视图:

can_view_details = True

从列表视图中删除列很容易,只需为 column_exclude_list 参数传递一个列名列表:

column_exclude_list = ['password', ]

要使列可搜索或使用它们进行过滤,请指定列名列表:

column_searchable_list = ['name', 'email']
column_filters = ['country']

为了获得更快的编辑体验,请在列表视图中启用内联编辑:

column_editable_list = ['name', 'last_name']

或者,让添加和编辑表单显示在列表页面的模态窗口中,而不是专门的创建和编辑页面:

create_modal = True
edit_modal = True

您可以通过指定选择列表来限制文本字段的可能值:

form_choices = {
    'title': [
        ('MR', 'Mr'),
        ('MRS', 'Mrs'),
        ('MS', 'Ms'),
        ('DR', 'Dr'),
        ('PROF', 'Prof.')
    ]
}

从创建和编辑表单中删除字段:

orm_excluded_columns = ['last_name', 'email']

要指定 WTForms 字段参数:

form_args = {
    'name': {
        'label': 'First Name',
        'validators': [required()]
    }
}

或者,为用于呈现这些字段的 WTForms 小部件指定参数:

form_widget_args = {
    'description': {
        'rows': 10,
        'style': 'color: black'
    }
}

当您的表单包含外键时,通过 ajax 加载那些相关模型,使用:

form_ajax_refs = {
    'user': {
        'fields': ['first_name', 'last_name', 'email'],
        'page_size': 10
    }
}

要过滤通过 ajax 加载的结果,您可以使用:

form_ajax_refs = {
    'active_user': QueryAjaxModelLoader('user', db.session, User,
                                 filters=["is_active=True", "id>1000"])
}


内联管理相关模型:

inline_models = ['post', ]

这些内联表单可以自定义。查看 inline_models()API 文档。要启用模型视图的 csv 导出:

can_export = True

这将向导出记录的模型视图添加一个按钮,在 export_max_rows 处截断。

分组视图

添加视图时,为类别参数指定一个值以将菜单中的相关视图组合在一起:

admin.add_view(UserView(User, db.session, category="Team"))
admin.add_view(ModelView(Role, db.session, category="Team"))
admin.add_view(ModelView(Permission, db.session, category="Team"))

这将创建一个名为“团队”的顶级菜单项,以及一个包含指向三个视图的链接的下拉菜单。要在这些下拉列表中嵌套相关视图,请使用 add_sub_category 方法:

admin.add_sub_category(name="Links", parent_name="Team")

并向菜单添加任意超链接:

admin.add_link(MenuLink(name='Home Page', url='/', category='Links'))

添加您自己的视图

对于您的需求非常具体并且您很难通过内置的 ModelView 类来满足它们的情况,Flask-Admin 使您可以轻松地完全控制并向界面添加您自己的视图。

单例视图

可以通过扩展 BaseView 类并定义您自己的视图方法来添加一组独立视图(不依赖于任何特定模型)。例如,要添加一个显示来自第 3 方 API 的一些分析数据的页面:

from flask_admin import BaseView, expose

class AnalyticsView(BaseView):
    @expose('/')
    def index(self):
        return self.render('analytics_index.html')

admin.add_view(AnalyticsView(name='Analytics', endpoint='analytics'))

这将为您的视图添加指向导航栏的链接。请注意,它是在“/”(根 URL)处提供的。这是对独立视图的限制:至少,每个视图类都需要至少一种方法来为它的根视图提供服务。上面示例的 analytics_index.html 模板可能类似于:

{% extends 'admin/master.html' %}
{% block body %}
  <p>Here I'm going to display some data.</p>
{% endblock %}

通过扩展 admin/master.html 模板,即使在严格控制页面内容的情况下,您也可以保持一致的用户体验。

覆盖内置视图


在某些情况下,您可能需要大部分内置的 ModelView 功能,但又想替换默认的创建、编辑或列表视图之一。为此,您可以仅覆盖有问题的视图,并且指向它的所有链接仍将按您期望的那样运行:

from flask_admin.contrib.sqla import ModelView

# Flask and Flask-SQLAlchemy initialization here

class UserView(ModelView):
    @expose('/new/', methods=('GET', 'POST'))
    def create_view(self):
    """
       自定义创建视图。
    """

    return self.render('create_user.html')

使用内置模板

Flask-Admin 使用 Jinja2 模板引擎。

扩展内置模板


与其完全覆盖内置模板,不如扩展它们。这将使您将来更容易升级到新的 Flask-Admin 版本。在内部,Flask-Admin 模板派生自 admin/master.html 模板。您可以扩展的三个最有趣的模板可能是:

  • admin/model/list.html
  • admin/model/create.html
  • admin/model/edit.html

要使用您自己的功能扩展默认编辑模板,请在 templates/microblog_edit.html 中创建一个类似于以下内容的模板:

{% extends 'admin/model/edit.html' %}

{% block body %}
    <h1>MicroBlog Edit View</h1>
    {{ super() }}
{% endblock %}

现在,要让您的视图类使用此模板,请设置适当的类属性:

class MicroBlogModelView(ModelView):
    edit_template = 'microblog_edit.html'
    # create_template = 'microblog_create.html'
    # list_template = 'microblog_list.html'
    # details_template = 'microblog_details.html'
    # edit_modal_template = 'microblog_edit_modal.html'
    # create_modal_template = 'microblog_create_modal.html'
    # details_modal_template = 'microblog_details_modal.html'

如果要使用自己的基本模板,则在初始化期间将模板的名称传递给管理构造函数:

admin = Admin(app, base_template='microblog_master.html')

覆盖内置模板

要完全控制管理界面的样式和布局,您可以覆盖所有内置模板。请记住,从一个版本的 Flask-Admin 到下一个版本,模板会略有不同,因此一旦开始覆盖它们,升级包版本时需要小心。

要覆盖任何内置模板,只需将它们从 Flask-Admin 源复制到项目的 templates/admin/ 目录中。只要文件名保持不变,项目目录中的模板就会自动优先于内置模板。

可用模板代码块

Flask-Admin admin/master.html 中定义了一个基本模板,所有其他管理模板都派生自该模板。这个模板是一个指向 admin/base.html 的代理,它定义了以下代码块:

代码块名描述
head_meta页眉中的页面元数据
title页面标题
head_css标头中包含各种 CSS
headHTML head 中的空块,以防你想在那里放一些东西
page_body页面布局
brand菜单栏中的徽标
main_menu主菜单
menu_links链接菜单
access_control菜单右侧的部分(可用于添加登录/注销按钮)
messages警报和各种消息
body内容(即您的视图将显示的位置)
tail内容下方空白区域
表1.1 可用代码块


除了从 admin/master.html 继承的所有块之外,admin/model/list.html 模板还包含以下代码块:

代码块名描述
model_menu_bar菜单栏
model_list_table表格容器
list_header表格标题行
list_row_actions_header操作标题
list_row单排
list_row_actions带有编辑/删除/等按钮的行操作单元格
empty_list_message如果没有找到模型,将显示的消息
图1.2 列表代码块


查看 https://github.com/flask-admin/flask-admin/tree/master/examples/custom-layout 中的布局示例,了解如何对管理界面进行全面的风格控制。

环境变量

在使用任何扩展 admin/master.html 的模板时,您可以访问少量环境变量:

变量名描述
admin_view当前管理视图
admin_base_template基本模板名称
_gettextBabel gettext
_ngettextBabel ngettext
h帮助文档来自helpers 模块
表 1.3 环境变量

生成网址

为特定视图生成 URL,请使用带点前缀的 url_for

from flask import url_for

class MyView(BaseView):
    @expose('/')
    def index(self):
        #获取测试视图方法的 URL
        user_list_url = url_for('user.index_view')
        return self.render('index.html', user_list_url=user_list_url)

还可以通过以下方式引用特定记录:

# 编辑记录 #1 的视图(重定向回 index_view)
url_for('user.edit_view', id=1, url=url_for('user.index_view'))

引用 ModelView 实例时,调用 url_for 时使用模型的小写名称作为前缀。可以通过为每个视图指定一个唯一端点并将其用作前缀来引用其他视图。所以,你可以使用:

url_for('analytics.index')

如果您的视图端点定义如下:

admin.add_view(CustomView(name='Analytics', endpoint='analytics'))
赞(2) 打赏
转载请附上原文出处链接:胖蔡说技术 » Flask 中使用flask-admin实现数据模型绑定视图
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏