flask扩展包 --- Bootstrap-Flask

简介:

Bootstrap-Flask是一个简化在Flask项目中集成前端开源框架Bootstrap过程的Flask扩展。使用Bootstrap可以快速的创建简洁、美观又功能全面的页面,而Bootstrap-Flask让这一过程更加简单和高效。

安装:

pip install bootstrap-flask

初始化:

from flask_bootstrap import Bootstrap
from flask import Flask

app = Flask(__name__)
bootstrap = Bootstrap(app)

工厂函数穿件程序实例:

from flask_bootstrap import Bootstrap
from flask import Flask

bootstrap = Bootstrap()

def create_app():
  app = Flask(__name__)
  bootstrap.init_app(app)
  return app

Bootstrap-Flask提供的功能

  • 2个资源加载函数
    在简单的示例程序中或者开发中,你可以使用他提供的两个快捷方法生成Bootstrap资源引用代码:
<head>
{{ bootstrap.load_css() }}
</head>
<body>
...
{{ bootstrap.load_js() }}
</body>
  • 7个快捷渲染宏
    目前,Bootstrap-Flask一共提供了7个宏,分别用来快捷渲染各类Bootstrap页面组件,并提供了对扩展Flask-WTF、Flask-SQLAlchemy的支持
Bootstrap-Flask配置变量

使用方法简单,例如渲染Flask-WTF(WTForms) 的表单类的render_form()宏为例,你只需要从对应的模板路径导入宏,然后调用即可并传入必要参数:

  • 用户信息修改提交表单函数
@user_bp.route('/settings/profile', methods=['GET', 'POST'])
# 用户重新验证登录获取一个新的session
@login_required
def edit_profile():
    form = EditProfileForm()
    # 如果用户点击了提交按钮对表单提交的字段进行验证,无误后更新数据库
    if form.validate_on_submit():
        current_user.name = form.name.data
        current_user.username = form.username.data
        current_user.bio = form.bio.data
        current_user.website = form.website.data
        current_user.location = form.location.data
        db.session.commit()
        # 修改成功后弹框提示修改成功
        flash('Profile updated.', 'success')
        # 自动跳转到主页,并修改渲染的用户名
        return redirect(url_for('.index', username=current_user.username))
    # 表单未修改时始终显示之前的用户信息
    form.name.data = current_user.name
    form.username.data = current_user.username
    form.bio.data = current_user.bio
    form.website.data = current_user.website
    form.location.data = current_user.location
    # 将用户数据渲染到表单中
    return render_template('user/settings/edit_profile.html', form=form)
  • 用户修改个人信息渲染模板
{% extends 'user/settings/base.html' %}
{% from 'bootstrap/form.html' import render_form %}

{% block title %}Edit Profile{% endblock %}

{% block setting_content %}
    <div class="card w-100 bg-light">
        <h3 class="card-header">Edit Profile</h3>
        <div class="card-body">
            {{ render_form(form) }}
        </div>
    </div>
{% endblock %}

利用reder_field()渲染表单字段

  • 渲染用户发布的图片描述
@main_bp.route('/photo/<int:photo_id>')
def show_photo(photo_id):
    photo = Photo.query.get_or_404(photo_id)
    page = request.args.get('page', 1, type=int)
    per_page = current_app.config['ALBUMY_COMMENT_PER_PAGE']
    pagination = Comment.query.with_parent(photo).order_by(Comment.timestamp.asc()).paginate(page, per_page)
    comments = pagination.items

    comment_form = CommentForm()
    description_form = DescriptionForm()
    tag_form = TagForm()

    description_form.description.data = photo.description
    return render_template('main/photo.html', photo=photo, comment_form=comment_form,
                           description_form=description_form, tag_form=tag_form,
                           pagination=pagination, comments=comments)
  • 用户发布图片信息渲染模板
<div id="description-form">
                <form action="{{ url_for('.edit_description', photo_id=photo.id) }}" method="post">
                    {{ description_form.csrf_token }}
                    {{ render_field(description_form.description) }}
                    <a class="btn btn-light btn-sm" id="cancel-description">Cancel</a>
                    {{ render_field(description_form.submit, class='btn btn-success btn-sm') }}
                </form>
            </div>
  • 利用render_pagination()宏渲染一个标准的分页导航部件:
@main_bp.route('/')
def index():
    # 验证是否未登录状态
    if current_user.is_authenticated:
        # 获取参数page不传默认为1,强制转换类型
        page = request.args.get('page', 1, type=int)
        per_page = current_app.config['ALBUMY_PHOTO_PER_PAGE']
        pagination = Photo.query \
            .join(Follow, Follow.followed_id == Photo.author_id) \
            .filter(Follow.follower_id == current_user.id) \
            .order_by(Photo.timestamp.desc()) \
            .paginate(page, per_page)
        photos = pagination.items
    else:
        pagination = None
        photos = None
    tags = Tag.query.join(Tag.photos).group_by(Tag.id).order_by(func.count(Photo.id).desc()).limit(10)
    return render_template('main/index.html', pagination=pagination, photos=photos, tags=tags, Collect=Collect)

这里关注的几个要点:

a. 路由中添加页面属性"/" ,这样网址中就可以添加页面参数

b. 函数添加参数page,默认值为1

c. 查询函数添加 .paginate(page, per_page),返回一个paginate对象

d. render_template 传入paginate对象,和数据信息paginate.items

# index.html渲染
 {% if photos %}
        {{ render_pagination(pagination, align='center') }}
    {% endif %}
模板渲染结果

利用render_nav_item() 渲染一个 导航条目

  • 导航条目 home, explore
{# 导入import render_nav_item #}
{% from 'bootstrap/nav.html' import render_nav_item %}
{# 导航栏点击 Home 渲染 main.index模板,点击Explore渲染 main.explore模 #}
<div class="navbar-nav mr-auto">
                    {{ render_nav_item('main.index', 'Home') }}
                    {{ render_nav_item('main.explore', 'Explore') }}
                    <form class="form-inline my-2 my-lg-0" action="{{ url_for('main.search') }}">
                        <input type="text" name="q" class="form-control mr-sm-1" placeholder="Photo, tag or user"
                               required>
                        <button class="btn btn-light my-2 my-sm-0" type="submit">
                            <span class="oi oi-magnifying-glass"></span>
                        </button>
                    </form>
                </div>

利用 render_breadcrumb_item 渲染面包屑条目

{% from 'bootstrap/nav.html' import render_breadcrumb_item %}
{# 点击Dashboard Home 渲染 admin.index模板 #}
{# 点击Manage User 渲染 admin.manage_user模板 #}
{# 点击Edit Profile 渲染 admin.edit_profile_admin模板 #}
<ol class="breadcrumb">
            {{ render_breadcrumb_item('admin.index', 'Dashboard Home') }}
            {{ render_breadcrumb_item('admin.manage_user', 'Manage User') }}
            {{ render_breadcrumb_item('admin.edit_profile_admin', 'Edit Profile') }}
</ol>
面包屑条目
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342