返回文章列表

Flask 訊息閃現與資料函式庫搜尋功能實作

本文介紹如何在 Flask Web 應用程式中實作訊息閃現機制,提升使用者經驗,並示範如何使用 SQLAlchemy 進行資料函式庫搜尋,以及如何使用 WTForms 建立和處理 Web 表單,包含表單驗證和資料函式庫互動。

Web 開發 後端開發

在 Flask 應用程式中,我們可以利用訊息閃現機制,在使用者完成特定操作後,提供即時的反饋訊息,例如在新增、修改或刪除資料後,顯示成功或失敗的提示。這能有效提升使用者經驗,讓使用者清楚知道操作結果。此外,資料函式庫搜尋功能也是 Web 應用程式不可或缺的一部分,透過 SQLAlchemy 可以輕鬆地根據不同條件篩選資料,並將結果呈現給使用者。同時,WTForms 提供了簡潔易用的方式來建立和管理 Web 表單,有效簡化表單處理流程,並確保資料的有效性和安全性。結合這些技術,可以開發更完善、使用者友善的 Web 應用程式。

提升使用者經驗:訊息閃現功能實作

在開發高品質的Web應用程式時,提供使用者適當的互動反饋至關重要。當使用者完成某項操作,例如建立新產品並被重新導向至該產品頁面時,適時地告知使用者操作結果是一種良好的實踐。本篇內容將介紹如何使用訊息閃現(Flash Messages)機制來提升使用者經驗。

準備工作

首先,我們需要在現有的產品目錄應用程式中加入訊息閃現功能。同時,必須為應用程式設定一個秘密金鑰(Secret Key),因為Session機制依賴於此金鑰,否則在嘗試閃現訊息時應用程式將會報錯。

實作步驟

1. 設定秘密金鑰

flask_catalog_template/my_app/__init__.py 檔案中為應用程式新增一個秘密金鑰:

app.secret_key = 'some_random_key'

2. 修改產品建立處理函式

接下來,在 flask_catalog_template/my_app/catalog/views.py 檔案中修改 create_product() 處理函式,以便在成功建立產品後向使用者閃現一則訊息。同時,這個函式現在支援透過網頁表單建立產品的功能,這使得示範訊息閃現的效果更加直觀。

@catalog.route('/product-create', methods=['GET', 'POST'])
def create_product():
    if request.method == 'POST':
        name = request.form.get('name')
        price = request.form.get('price')
        categ_name = request.form.get('category')
        category = Category.query.filter_by(name=categ_name).first()
        if not category:
            category = Category(categ_name)
        product = Product(name, price, category)
        db.session.add(product)
        db.session.commit()
        flash('The product %s has been created' % name, 'success')
        return redirect(url_for('catalog.product', id=product.id))
    return render_template('product-create.html')

在上述程式碼中,當成功建立產品後,會呼叫 flash() 函式閃現一則訊息。第一個引數是訊息內容,第二個引數是訊息類別,可以根據這個類別決定要顯示的提示訊息型別。

3. 新增產品建立表單範本

新增一個名為 product-create.html 的範本檔案,位於 flask_catalog_template/my_app/templates/ 目錄下,用於渲染產品建立表單。

{% extends 'home.html' %}

{% block container %}
<div class="top-pad">
    <form class="form-horizontal" method="POST" action="{{ url_for('catalog.create_product') }}" role="form">
        <!-- 表單內容省略 -->
        <button type="submit" class="btn btn-default">Submit</button>
    </form>
</div>
{% endblock %}

4. 修改基礎範本以顯示閃現訊息

最後,修改基礎範本 base.html,使其能夠顯示閃現的訊息。在 <div class="container"> 內部、 {% block container %} 之前加入以下程式碼:

<br/>
<div>
    {% for category, message in get_flashed_messages(with_categories=true) %}
    <div class="alert alert-{{category}} alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        {{ message }}
    </div>
    {% endfor %}
</div>

這段程式碼利用 get_flashed_messages() 函式取得所有閃現的訊息,並根據訊息類別顯示對應的提示框。

結果示範

存取 http://127.0.0.1:5000/product-create 並填寫產品建立表單,提交後將重新導向至新建立的產品頁面,並在頁面頂部顯示一則成功建立產品的提示訊息。

資料函式庫搜尋功能的實作

在Web應用程式中,能夠根據特定條件搜尋資料函式庫記錄是一項基本需求。本文將介紹如何在SQLAlchemy中實作基本的資料函式庫搜尋功能。

實作搜尋功能

flask_catalog_template/my_app/catalog/views.py 中新增一個處理函式,用於根據不同條件搜尋產品:

from sqlalchemy.orm import join

@catalog.route('/product-search')
@catalog.route('/product-search/<int:page>')
def product_search(page=1):
    name = request.args.get('name')
    price = request.args.get('price')
    company = request.args.get('company')
    category = request.args.get('category')
    products = Product.query
    
    # #### 內容解密:
    # 這裡根據不同的搜尋條件逐步過濾產品查詢結果。
    # 如果提供了名稱,則使用名稱進行模糊搜尋。
    if name:
        products = products.filter(Product.name.like('%' + name + '%'))
    
    # 如果提供了價格,則精確比對該價格的產品。
    if price:
        products = products.filter(Product.price == price)
    
    # 如果提供了公司名稱,則對公司名稱進行模糊搜尋。
    if company:
        products = products.filter(Product.company.like('%' + company + '%'))
    
    # 如果提供了類別,則透過Join操作與Category表進行關聯查詢。
    if category:
        products = products.select_from(join(Product, Category)).filter(Category.name.like('%' + category + '%'))
    
    # 將最終的查詢結果分頁顯示。
    return render_template('products.html', products=products.paginate(page, 10))

使用搜尋功能

可以透過存取類別似 http://127.0.0.1:5000/product-search?name=iPhone 的URL來搜尋名稱包含 “iPhone” 的產品。使用者可以根據不同的條件組合進行搜尋,例如價格、公司名稱或類別等。

使用WTForms建立Web表單

表單處理是任何Web應用程式的重要組成部分。在許多情況下,表單的存在對於Web應用程式至關重要,例如使用者需要登入或提交某些資料,或應用程式需要使用者輸入資料。表單的驗證與表單本身一樣重要,甚至更為重要。以互動方式向使用者呈現這些資訊可以為應用程式增加很多價值。

設計和實作表單

有多種方法可以在Web應用程式中設計和實作表單。隨著Web應用程式的發展,表單驗證和向使用者傳達正確的訊息變得非常重要。可以使用JavaScript和HTML5在前端實作客戶端驗證。伺服器端驗證在為應用程式新增安全性方面發揮著更重要的作用,而不是使用者互動。伺服器端驗證可以防止錯誤的資料進入資料函式庫,從而遏制詐欺和攻擊。

WTForms的功能

WTForms提供了許多預設的欄位和伺服器端驗證,從而提高了開發速度並減少了整體工作量。它還提供了編寫自定義驗證和自定義欄位的靈活性。

安裝Flask-WTF

本章將使用一個名為Flask-WTF的Flask擴充套件,它提供了WTForms和Flask之間的整合,負責處理一些重要且瑣碎的事情,使我們的應用程式更加安全和有效。可以透過以下命令安裝它:

$ pip install Flask-WTF

將SQLAlchemy模型資料表示為表單

首先,我們將使用SQLAlchemy模型建立一個表單。在這個範例中,我們將使用本文前面使用的產品模型,並新增功能,透過Web表單建立產品。

準備工作

我們將使用第4章《Working with Views》中使用的目錄應用程式,並為Product模型開發一個表單。

實作步驟

如果您回憶一下,Product模型在models.py檔案中如下所示:

class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    price = db.Column(db.Float)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    category = db.relationship('Category', backref=db.backref('products', lazy='dynamic'))

首先,我們將在models.py中建立一個ProductForm類別,它將繼承自flask_wtf提供的FlaskForm類別,以表示Web表單所需的欄位:

from wtforms import StringField, DecimalField, SelectField
from flask_wtf import FlaskForm

class ProductForm(FlaskForm):
    name = StringField('Name')
    price = DecimalField('Price')
    category = SelectField('Category', coerce=int)

程式碼解析:

from wtforms import StringField, DecimalField, SelectField
from flask_wtf import FlaskForm

class ProductForm(FlaskForm):
    name = StringField('Name')
    price = DecimalField('Price')
    category = SelectField('Category', coerce=int)

內容解密:

  1. 匯入必要的模組:從wtforms匯入StringFieldDecimalFieldSelectField,從flask_wtf匯入FlaskForm
  2. 定義ProductForm類別:該類別繼承自FlaskForm,用於表示Web表單。
  3. name欄位:使用StringField型別,表示需要文字資料的欄位。
  4. price欄位:使用DecimalField型別,將資料解析為Python的Decimal資料型別。
  5. category欄位:使用SelectField型別,表示只能從先前建立的類別中選擇的欄位。coerce=int引數表示將傳入的資料強制轉換為整數值。

views.py中的create_product()處理函式現在應該容納前面建立的表單:

from my_app.catalog.models import ProductForm

@catalog.route('/product-create', methods=['GET', 'POST'])
def create_product():
    form = ProductForm(meta={'csrf': False})
    categories = [(c.id, c.name) for c in Category.query.all()]
    form.category.choices = categories
    
    if request.method == 'POST':
        name = request.form.get('name')
        price = request.form.get('price')
        category = Category.query.get_or_404(request.form.get('category'))
        product = Product(name, price, category)
        db.session.add(product)
        db.session.commit()
        flash('The product %s has been created' % name, 'success')
        return redirect(url_for('catalog.product', id=product.id))
    
    return render_template('product-create.html', form=form)

程式碼解析:

from my_app.catalog.models import ProductForm

@catalog.route('/product-create', methods=['GET', 'POST'])
def create_product():
    form = ProductForm(meta={'csrf': False})
    categories = [(c.id, c.name) for c in Category.query.all()]
    form.category.choices = categories
    
    if request.method == 'POST':
        name = request.form.get('name')
        price = request.form.get('price')
        category = Category.query.get_or_404(request.form.get('category'))
        product = Product(name, price, category)
        db.session.add(product)
        db.session.commit()
        flash('The product %s has been created' % name, 'success')
        return redirect(url_for('catalog.product', id=product.id))
    
    return render_template('product-create.html', form=form)

內容解密:

  1. 匯入ProductForm:從my_app.catalog.models匯入ProductForm
  2. 定義create_product函式:處理/product-create路由,支援GET和POST方法。
  3. 建立ProductForm例項:停用CSRF保護。
  4. 取得類別列表:查詢所有類別並將其格式化為列表。
  5. 設定類別選項:將類別列表指定給表單的category欄位。
  6. 處理POST請求:取得表單資料,建立新產品並提交到資料函式庫。
  7. 顯示成功訊息並重定向:建立成功後顯示訊息並重定向到產品頁面。
  8. 渲染表單頁面:如果是GET請求,渲染包含表單的頁面。