flask 項目中使用 bootstrapFileInput(基礎篇)

bootstrap 為 flask 使用人員提供了一個非常優美且有效的前端頁面組件,但是完美之處還存在些許缺陷,比如文件的上傳功能.而 bootstrap-fileinput 是基于 bootstrap 的控件,非常完美的填補了這個空缺.

注意: 本文是基于 bootstrap-fileinput v4.4.2. github 地址: https://github.com/kartik-v/bootstrap-fileinput

注意: 本文是主要是以 http://plugins.krajee.com/file-input/demo 示例為基礎進行講解.

創建藍圖 basic

創建方法請參照 flask 項目中使用 bootstrapFileInput(構建篇) 中 lib 藍圖的創建方法,此處不在贅述.

構建基礎 html 模板

app/basic/templates/basic_common/base.html 內容如下:

<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
        <meta name="description" content="">
        <meta name="author" content="">
        <link rel="icon" href="{{ url_for('lib.static', filename='favicon.ico')}}">

        <title>{% block title %}{% endblock %}</title>
        {% block css %}
            <!-- 新 Bootstrap 核心 CSS 文件 -->
            <link rel="stylesheet" href="{{ url_for('lib.static', filename='css/bootstrap.min.css') }}">

            <!-- 可選的Bootstrap主題文件(一般不用引入) -->
            <link rel="stylesheet" href="{{ url_for('lib.static', filename='css/bootstrap-theme.min.css') }}">

            <!-- 個性化主題文件 -->
            <!-- font-awesome樣式主題文體 -->
            <link href="{{ url_for('lib.static',filename='css/font-awesome.css') }}" media="all" rel="stylesheet" type="text/css" />
            <!-- fileinput樣式主題文體 -->
            <link href="{{ url_for('lib.static',filename='css/fileinput.min.css') }}" media="all" rel="stylesheet" type="text/css" />
        {% endblock %}

        {% block js %}
            <!-- jQuery文件。務必在bootstrap.min.js 之前引入 -->
            <script src="{{ url_for('lib.static', filename='js/jquery.min.js') }}"></script>

            <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
            <script src="{{ url_for('lib.static', filename='js/bootstrap.min.js') }}"></script>

            <!-- 個性化 js 文件 -->
            <!-- piexif.min.js is only needed if you wish to resize images before upload to restore exif data.
             This must be loaded before fileinput.min.js -->
            <script src="{{ url_for('lib.static',filename='js/plugins/piexif.min.js') }}" type="text/javascript"></script>
            <!-- sortable.min.js is only needed if you wish to sort / rearrange files in initial preview.
                 This must be loaded before fileinput.min.js -->
            <script src="{{ url_for('lib.static',filename='js/plugins/sortable.min.js') }}" type="text/javascript"></script>
            <!-- purify.min.js is only needed if you wish to purify HTML content in your preview for HTML files.
                 This must be loaded before fileinput.min.js -->
            <script src="{{ url_for('lib.static',filename='js/plugins/purify.js') }}" type="text/javascript"></script>
            <!-- the main fileinput plugin file -->
            <script src="{{ url_for('lib.static',filename='js/fileinput.min.js') }}"></script>
            <!-- optionally if you need a theme like font awesome theme you can include
                it as mentioned below -->
            <script src="{{ url_for('lib.static',filename='js/themes/fa/theme.min.js') }}"></script>
            <!-- optionally if you need translation for your language then include
                locale file as mentioned below -->
            <script src="{{ url_for('lib.static',filename='js/locales/zh.js') }}"></script>

        {% endblock %}
    </head>

    <body>
        <div class="container">
            <div class="row">
                <div class="col-xs-12 col-sm-offset-2">
                    <div class="col-xs-12 col-sm-8">
                        {% block content %}

                        {% endblock %}
                    </div>
                </div>
            </div><!--/row-->
        </div><!--/.container-->
    </body>
</html>

base.html 模板引入 css 和 js 時的幾個坑

注意 css 和 js 文件的導入順序

  • 首先需要導入的 js 文件是 jquery.js.
  • 第二需要導入 bootstrap 相關的 css 和 js.
  • 第三需要導入 fileinput 相關的 css 和 js, 請注意項目中的注釋, 相關的文件導入也需要有先后順序的要求.

注意版本問題

  • 此項目所需的 jquery 是 jQuery v2.1.1.
  • 此項目所需的 bootstrap 是 v3.3.7 版本
  • 此項目所需的 fileinput 是 v4.4.2 的版本.

其它版本可能會有所不同.

注意 fileinput 使用模式

fileinput 有兩種使用模式,一種是利用 form 提交,一種是 ajax 方式提交.其中 ajax 提交方式,需要從 js 中進行設置, 并將類樣式 class 設置為 file-loading. 而非 ajax 提交方式需要引入 form 表單, 類樣式 class 需設置為 file, 本基礎示例都需要引入 form 表單.

基礎示例 1

模板內容

app/basic/templates/example_1.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例1 -- 自動展示縮略圖</h1>
<label class="control-label">Select File</label>
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-1" name="input-1" type="file" class="file">
</form>

{% endblock %}
{% block title %}
    基本示例1 -- 自動展示縮略圖
{% endblock %}

知識點:

  1. 需要引入 form 表單, 并支持文件上傳, 需設置 enctype="multipart/form-data".
  2. 由于 flask 項目是以 html 標簽的 name 屬性進行選擇元素, 該 input 標簽中需要設置 name 屬性.
  3. class 需要設置為 'file'.
  4. input 標簽的 type 屬性要設置為 file, 以便支持文件上傳.
  5. input 標簽由于沒有引入 multiple 屬性, 故不能實現選擇多文件功能.

視圖函數

app/basic/views.py 內容如下:

# -*- coding:utf-8 -*-
__author__ = '東方鶚'

from flask import render_template, request, current_app, redirect, url_for
from . import basic
from werkzeug.utils import secure_filename
import os


def allowed_file(filename):
    ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


@basic.route('/example_1', methods=['GET', 'POST'])
def example_1():
    if request.method == 'POST':
        file = request.files['input-1']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))

    return render_template('example_1.html')

知識點:

  1. allowed_file 函數是為了檢查所上傳的文件的格式, 主要實現方法是通過文件后綴來判斷文件的格式. 參考文檔: http://docs.jinkan.org/docs/flask/patterns/fileuploads.html
  2. secure_filename 函數是為了讓用戶上傳的文件的文件名更安全. 參考文檔: http://werkzeug.pocoo.org/docs/0.12/utils/#werkzeug.utils.secure_filename
  3. request.files['input-1'] 是為了獲得上傳的文件的對象. 此處的 'input-1' 對應的是 html 模板中 input 標簽的 name 屬性. 獲取多個上傳的文件需要用到 request.files.getlist('name屬性標簽'), 可得到一個文件對象的列表.
  4. 上傳的路徑是在 config.py 文件中設置的 UPLOAD_FOLDER 變量.

展示

image

基礎示例 2

模板內容

app/basic/templates/example_2.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例2 -- 隱藏展示縮略圖</h1>
<label class="control-label">Select File</label>
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-2" name="input-2" type="file" class="file"  data-show-preview="false">
</form>
{% endblock %}
{% block title %}
    基本示例2 -- 隱藏展示縮略圖
{% endblock %}

知識點:

  1. data-show-preview="false" 屬性將關閉文件選擇后預覽的功能, 既縮略圖功能.
  2. 實現打開/關閉文件選擇后的預覽功能也可以在js里進行設置:
$(document).on('ready', function() {
    $("#input-2").fileinput({
        show-preview: false
    });
});

視圖函數

views.py 視圖函數和示例1基本相同,不在贅述.

展示

image

基礎示例 3

模板內容

app/basic/templates/example_3.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例3 -- 利用 file input 屬性控制相關選項,如本例可實現多文件上傳,但不顯示上傳按鈕</h1>
<label class="control-label">Select File</label>
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-3" name="input3[]" type="file" class="file" multiple data-show-upload="false" data-show-caption="true">
</form>
{% endblock %}
{% block title %}
    基本示例3 -- 利用 file input 屬性控制相關選項,如本例可實現多文件上傳,但不顯示上傳按鈕
{% endblock %}

知識點:

  1. input 標簽里有 multiple 屬性, 可實現多文件選擇的功能.
  2. data-show-upload="false" 屬性將不顯示上傳按鈕, 默認為 true.
  3. data-show-caption="true" 屬性將顯示選擇文件的輸入框, 默認為 true. 框內將顯示將要選擇的文件的名稱.
  4. 同樣可以在 js 里實現相關功能.
$(document).on('ready', function() {
    $("#input-3").fileinput({
        show-upload: false,
        show-caption: true
    });
});

視圖函數

由于沒有上傳按鈕, 故無需處理選擇的文件. 視圖函數無需改變.

展示

image

基礎示例 4

模板內容

app/basic/templates/example_4.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例4 -- 設置屬性為只讀或不可用</h1>
<label class="control-label">Select File</label>
<label class="control-label">Readonly Input</label>
<input id="input-4a" type="file" class="file" readonly="true">
<label class="control-label">Disabled Input</label>
<input id="input-4b" type="file" class="file" disabled="true">
{% endblock %}
{% block title %}
    基本示例4 -- 設置屬性為只讀或不可用
{% endblock %}

知識點:

  1. 利用 readonly 或 disabled 屬性, 將選擇框設置為只讀或不可用.

視圖函數

由于無法選擇文件, 視圖函數無需改變.

展示

image

基礎示例 5

模板內容

app/basic/templates/example_5.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例5 -- 設置為單按鈕并隱藏文件選擇輸入框,在上傳時顯示上傳等待圖標</h1>
<label class="control-label">Select File</label>
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-5" name="input-5[]" type="file" multiple class="file-loading">
</form>
<script>
$(document).on('ready', function() {
    $("#input-5").fileinput({showCaption: false});
});
</script>
{% endblock %}
{% block title %}
    基本示例5 -- 設置為單按鈕并隱藏文件選擇輸入框,在上傳時顯示上傳等待圖標
{% endblock %}

知識點:

  1. 通過 js 設置 showCaption 的屬性為 false. 你也可以使用 data-show-caption 標簽屬性來設置.
  2. 注意樣式類 class 此處成了 file-loading. 這是一個很積極的變化, 表明你可以使用 ajax 提交方式來上傳文件啦. 你把 html 中的 form 表單去掉試試.

視圖函數

app/basic/views.py 內容如下:

...

@basic.route('/example_5', methods=['GET', 'POST'])
def example_5():
    if request.method == 'POST':
        files = request.files.getlist('input-5[]')
        for file in files:
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))

    return render_template('example_5.html')
    
...

知識點

  1. 使用 request.files.getlist() 來獲取上傳文件的對象列表.

展示

image

基礎示例 6

模板內容

app/basic/templates/example_6.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例6 -- 設置最大上傳的文件數為10</h1>
<label class="control-label">Select File</label>
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-6" name="input6[]" type="file" multiple class="file-loading">
</form>
<script>
$(document).on('ready', function() {
    $("#input-6").fileinput({
        showUpload: false,
        maxFileCount: 10,
        mainClass: "input-group-lg"
    });
});
</script>
{% endblock %}
{% block title %}
    基本示例6 -- 設置最大上傳的文件數為10
{% endblock %}

知識點:

  1. 通過 js 設置 showUpload 的屬性為 false. 你也可以使用 data-show-upload 標簽屬性來設置.
  2. 設置 maxFileCount 的屬性為 10, 表示最多可以一次性上傳 10 個文件.
  3. 設置 mainClass 的 屬性為 "input-group-lg", 基于 bootstrap 樣式. 文件的選擇框將變大.

視圖函數

由于沒有上傳按鈕, 故無需處理選擇的文件. 視圖函數無需改變.

展示

image

基礎示例 7

模板內容

app/basic/templates/example_7.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例7 -- 設置允許上傳的文件格式</h1>
<label class="control-label">Select File</label>
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-7" name="input-7[]" multiple type="file" class="file file-loading" data-allowed-file-extensions='["csv", "txt"]'>
</form>
{% endblock %}
{% block title %}
    基本示例7 -- 設置允許上傳的文件格式
{% endblock %}

知識點:

  1. 注意樣式類 class 此處成了 file-loading. 這是一個很積極的變化, 表明你可以使用 ajax 提交方式來上傳文件啦. 你把 html 中的 form 表單去掉試試.
  2. data-allowed-file-extensions='["csv", "txt"]' 設置上傳的文件的格式只能是 csv 或 txt 兩種格式

視圖函數

app/basic/views.py 內容如下:


...
@basic.route('/example_7', methods=['GET', 'POST'])
def example_7():
    if request.method == 'POST':
        files = request.files.getlist('input-7[]')
        for file in files:
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))

    return render_template('example_7.html')
    
...

知識點

  1. 此處的 allowed_file() 函數中的 ALLOWED_EXTENSIONS 變量, 最好和前端的一致.

展示

image

基礎示例 8

模板內容

app/basic/templates/example_8.html 內容如下:

{% extends 'basic_common/base.html' %}
{% block content %}
<h1>基本示例8 -- 使用rtl樣式,讓文件選擇按鈕居左</h1>
<span>注意:引入樣式文件的時候, css/fileinput-rtl.css 必須在 the css/fileinput.css 之后引入</span>
<div dir=rtl>
    <label class="control-label">Select File</label>
</div>
<!-- note that your input must just set the `rtl` data property of the plugin or in your javascript code -->
<form method="post" role="form" enctype="multipart/form-data">
    <input id="input-8" name="input-8[]" multiple type="file" class="file-loading">
</form>
<script>
$(document).on('ready', function() {
    $("#input-8").fileinput({
        rtl: true,
        allowedFileExtensions: ["jpg", "png", "gif"]
    });
});
</script>
{% endblock %}
{% block title %}
    基本示例8 -- 使用rtl樣式,讓文件選擇按鈕居左
{% endblock %}
{% block css %}
    {{ super() }}
    <link href="{{ url_for('lib.static',filename='css/fileinput-rtl.min.css') }}" media="all" rel="stylesheet" type="text/css" />
{% endblock %}

知識點:

  1. 注意 js 的內容, 引入了 rtl 屬性, 這需要先映入 css/fileinput-rtl.min.css 樣式表, 注意 flask 模板的導入方式. 此屬性將是按鈕的樣式反轉.
  2. allowedFileExtensions: ["jpg", "png", "gif"], 是在 js 中的設置方式.允許上傳的文件的格式為 "jpg", "png", "gif" 三種.你也可以使用 data 屬性選項來設置, data-allowed-file-extensions='["jpg", "png", "gif"]'.

視圖函數

app/basic/views.py 內容如下:


...
@basic.route('/example_8', methods=['GET', 'POST'])
def example_8():
    if request.method == 'POST':
        files = request.files.getlist('input-8[]')
        for file in files:
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))

    return render_template('example_8.html')
    
...

知識點

  1. 此處的 allowed_file() 函數中的 ALLOWED_EXTENSIONS 變量, 最好和前端的一致.

展示

image

本章源代碼下載:

<a class="btn btn-primary" >zip壓縮包</a>
<a class="btn btn-primary" >tar.gz壓縮包</a>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容