1. 程式人生 > >Flask:03-你離最美的web只差一個:bootstrap與表單

Flask:03-你離最美的web只差一個:bootstrap與表單

bootstrap與表單

Bootstrap是美國Twitter公司的設計師Mark Otto和Jacob Thornton合作基於HTML、CSS、JavaScript 開發的簡潔、直觀、強悍的前端開發框架,使得 Web 開發更加快捷. Bootstrap提供了優雅的HTML和CSS規範,它即是由動態CSS語言Less寫成。Bootstrap一經推出後頗受歡迎,一直是GitHub上的熱門開源專案,包括NASA的MSNBC(微軟全國廣播公司)的BreakingNews都使用了該專案。國內一些移動開發者較為熟悉的框架,如WeX5前端開源框架等,也是基於Bootstrap原始碼進行效能優化而來。

flask-boostrap

  • 說明:在flask中使用bootstrap,可以通過該擴充套件庫完成。

  • 安裝:pip install flask-bootstrap

  • 使用:

    from flask_bootstrap import Bootstrap
    
    bootstrap = Bootstrap(app)
    
  • 模板

    {# 繼承自bootstrap基礎模板 #}
    {% extends 'bootstrap/base.html' %}
    
    {% block title %}標題{% endblock %}
    
    {% block content %}
        <div class="container">預設內容</div
    >
    {% endblock %}
  • bootstrap基礎模板中的block

    | block | 說明 || ———- | —————- || doc | 整個HTML文件 || html | 整個html標籤 || head | 整個head標籤 || metas | 一組meta標籤 || styles | 一組link標籤 || body | 整個body標籤 || navbar | 導航條 || content | 頁面內容 || scripts | 一組scripts標籤 |

    提示:當重寫一個block後,原來的顯示效果全沒了,很可能是因為沒有寫{{ super() }}

載入靜態資源

  • flask中靜態資源預設存放在static目錄下,因此目錄結構如下:

    project/        # 專案目錄
        manage.py            # 啟動控制檔案
        templates/            # 模板檔案目錄
        static/                # 靜態資源目錄
            img/                # 圖片
            css/                # css檔案
            js/                    # js檔案
            favicon.ico            # 收藏夾圖示
    
  • 載入靜態資原始檔

    {# 繼承自自定義的基礎模板 #}
    {% extends 'base.html' %}
    
    {% block title %}使用者登入{% endblock %}
    
    {% block page_content %}
        <h1>歡迎登入...</h1>
        <div class="test"></div>
        {# 載入圖片資源 #}
        {# 靜態資源載入的目錄static,提前在img資料夾儲存一個圖片xxx.jpg #}
        <img width="300" src="{{ url_for('static', filename='img/xxx.jpg') }}">
    {% endblock %}
    
    {% block styles %}
        {{ super() }}
        {# 載入CSS檔案:css檔案可以從bootstrap中貼上一個過來 #}
        <link href="{{ url_for('static', filename='css/common.css') }}" type="text/css" rel="stylesheet" />
    {% endblock %}
    
    {% block head %}
        {{ super() }}
        {# 載入網站收藏夾小圖示:ico檔案自行從百度下載一個ico檔案 #}
        <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}" />
    {% endblock %}
    
    {% block scripts %}
        {{ super() }}
        {# 載入JS檔案:js檔案可以從bootstrap中貼上一個過來 #}
        <script type="text/javascript" src="{{ url_for('static', filename='js/common.js') }}"></script>
    {% endblock %}
    

原生表單

  • 準備模板檔案

    <form method="get" action="{{ url_for('check') }}">
        使用者名稱:<input name="username" /><br />
        <input type="submit" />
    </form>
    
  • 新增檢視函式,渲染模板檔案

    @app.route('/login/')
    def login():
        return render_template('login.html')
    
  • 校驗提交的請求

    @app.route('/check/', methods=['GET', 'POST'])
    def check():
        # args:所有的GET引數
        # return request.args.get('username', '提交失敗')
        # form:所有的POST引數
        # return request.form.get('username', '提交失敗')
        # values:所有的GET/POST引數
        return request.values.get('username', '提交失敗')
    
  • 一個路由可以接收多種請求

    @app.route('/login/', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            return request.form.get('username', '登入失敗')
        return render_template('login.html')
    

flask-wtf

  • 說明:表單處理的擴充套件庫,提供了CSRF、欄位校驗等實用功能,實用非常方便。

  • 安裝:pip install flask-wtf

  • 使用:

    • 建立表單類:
    # 匯入表單類的基類
    from flask_wtf import FlaskForm
    # 匯入欄位型別
    from wtforms import StringField, SubmitField
    # 匯入相關驗證器
    from wtforms.validators import Length
    
    # 建立表單類
    class NameForm(FlaskForm):
        # name = StringField('使用者名稱')
        # submit = SubmitField('提交')
        name = StringField('使用者名稱', validators=[Length(3, 6, message='使用者名稱必須是3~6個字元')])
        submit = SubmitField('提交')
    
    • 新增檢視函式,建立表單物件,並分配的模板中
      @app.route('/', methods=['GET', 'POST'])
      def index():
          # 建立表單物件
          form = NameForm()
          # 判斷是否是有效的提交
          if form.validate_on_submit():
              return form.name.data
          # 在模板檔案中渲染表單,form.html可以自己寫一個,也可以百度一個
          return render_template('form.html', form=form)
    
  • 原生渲染表單

    {# 原生渲染 #}
    <form method="post">
        {# CSRF欄位 #}
        {{ form.hidden_tag() }}
        {# name欄位 #}
        {{ form.name.label() }}{{ form.name(id='xx', class='yy') }}
        {% for e in form.name.errors %}
            <div>{{ e }}</div>
        {% endfor %}
        {# 提交按鈕 #}
        {{ form.submit() }}
    </form>
    
  • 使用bootstrap進行渲染

    {% extends 'bootstrap/base.html' %}
    
    {# 匯入快速渲染表單的巨集 #}
    {% from 'bootstrap/wtf.html' import quick_form %}
    
    {% block title %}bootstrap渲染表單類{% endblock %}
    
    {% block content %}
        <div class="container">
            {# 在合適的位置渲染表單 #}
            {{ quick_form(form) }}
        </div>
    {% endblock %}
    
  • POST重定向到GET:瀏覽器會記錄最後的請求狀態,若最後請求時POST,點選重新整理時會提示再次提交表單。

    @app.route('/', methods=['GET', 'POST'])
    def index():
        # 建立表單物件
        form = NameForm()
        # 判斷是否是有效的提交
        if form.validate_on_submit():
            session['name'] = form.name.data
            return redirect(url_for('index'))
        name = session.get('name')
        # 在模板檔案中渲染表單
        return render_template('form2.html', form=form, name=name)
    
  • 常見欄位型別:請自行測試

    | 欄位型別 | 說明 || ——————- | —————————- || StringField | 普通文字 || SubmitField | 提交按鈕 || PasswordField | 密文文字 || HiddenField | 隱藏欄位 || RadioField | 單選框 || BooleanField | 複選框 || SelectField | 下拉框 || FileField | 檔案上傳 || TextAreaField | 文字域 || IntegerField | 文字欄位,值為整數 || FloatField | 文字欄位,值為浮點數 || DateField | datetime.date型別 || DateTimeField | datetime.datetime型別 |

  • 常見驗證器:請自行測試

    | 驗證器 | 說明 || —————— | —————————- || Length | 規定字元長度 || DataRequired | 確保欄位有值(提示資訊與所寫的不一致) || Email | 郵箱格式 || IPAddress | IP地址 || NumberRange | 數值的範圍 || URL | 統一資源定位符格式 || EqualTo | 驗證兩個欄位的一致性 || Regexp | 正則校驗 |

  • 自定義欄位驗證函式

    # 建立表單類
    class NameForm(FlaskForm):
          。。。
        # 欄位校驗函式:'validate_欄位名'
        def validate_name(self, field):
            if len(field.data) < 6:
                raise ValidationError('使用者名稱不能少於6個字元')
    

訊息閃爍

  • 說明:

    當用戶發出請求後,狀態發生了改變,需要系統給出警告提示等資訊時,通常都是彈出一條訊息,指示使用者下一步的操作,使用者可以手動關閉或自動消失,整個過程不會影響頁面的正常顯示。

  • 使用:

    • 在需要閃爍訊息時,使用flash函式儲存閃爍訊息
    @app.route('/', methods=['GET', 'POST'])
    def index():
        # 建立表單物件
        form = NameForm()
        # 判斷是否是有效的提交
        if form.validate_on_submit():
            # 最後一次提交的名字
            last_name = session.get('name')
            # 如果存在最後提交的名字,且最後提交的名字與之前儲存的名字不相同時
            if last_name and last_name != form.name.data:
                flash('大哥,又換名字了^_^')
            session['name'] = form.name.data
            return redirect(url_for('index'))
        name = session.get('name')
        # 在模板檔案中渲染表單
        return render_template('form2.html', form=form, name=name)
    
    • 在模板檔案中提供get_flashed_messages函式獲取閃爍訊息並渲染:
    {% for message in get_flashed_messages() %}
    {# 閃爍訊息檔案可以從bootstrap中貼上一個過來 #}
    <div class="alert alert-warning alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span>
        </button>
        {{ message }}
    </div>
    {% endfor %}
    

    說明:上面是從bootstrap貼上的可消失的警告框。

flask-moment

  • 說明:專門負責資料本地化顯示的擴充套件庫,使用非常方便。

  • 安裝:pip install flask-moment

  • 使用:

    • python程式碼:
    from flask_moment import Moment
    
    moment = Moment(app)
    
    @app.route('/moment/')
    def mom():
        from datetime import datetime, timedelta
        current_time = datetime.utcnow() + timedelta(seconds=-360)
        return render_template('mom.html', current_time=current_time)
    
    • 模板檔案:
    {# 載入jQuery:依賴 #}
    {{ moment.include_jquery() }}
    
    {# 載入moment #}
    {{ moment.include_moment() }}
    
    {# 設定語言 #}
    {{ moment.locale('zh-CN') }}
    
    {# 簡單的格式化時間顯示 #}
    <div>時間:{{ moment(current_time).format('LLLL') }}</div>
    <div>時間:{{ moment(current_time).format('LLL') }}</div>
    <div>時間:{{ moment(current_time).format('LL') }}</div>
    <div>時間:{{ moment(current_time).format('L') }}</div>
    
    {# 自定義格式化時間顯示:如2018-05-20 01:03:14 #}
    <div>自定義:{{ moment(current_time).format('YYYY-MM-DD HH:mm:ss') }}</div>
    
    {# 顯示時間差 #}
    <div>發表於:{{ moment(current_time).fromNow() }}</div>