Web開發----Flask-Bootstrap , Flask-Mail , Flask-wtf表單

一、Flask中集成Bootstrap

1.Bootstrap簡介
Bootstrap(http://getbootstrap.com/)是Twitter 開發的一個開源框架,它提供的用戶界面組件可用於創建整潔且具有吸引力的網頁,而且這些網頁還能兼容所有現代Web 瀏覽器。
2.爲什麼需要在Flask中集成Bootstrap?
Flask模板集成Bootstrap。一般情況下Flask都是搭配Jinja2模板引擎來實現視圖展現,
不過現在Bootstrap比較流行,內置的樣式也比較好看,一些css樣式和js動態都封裝好了,有利於提高開發效率.
3.Flask中如何使用集成的Bootstrap?
要想在程序中集成Bootstrap,顯然要對模板做所有必要的改動。
不過,更簡單的方法是使用一個名爲Flask-Bootstrap (相當於我們寫的base.html模板)的Flask 擴展,簡化集成的過程。

  • (1) Flask-Bootstrap 使用pip安裝:
pip install -i https://pypi.douban.com/simple flask_bootstrap
  • (2) Flask 擴展一般都在創建程序實例時初始化,
    Flask_Bootstrap的初始化方法:
from flask_bootstrap import Bootstrap
bootstrap = Bootstrap(app)
  • (3)初始化Flask-Bootstrap 之後,就可以在程序中使用一個包含所有Bootstrap 文件的基模板base.html。
    文件位置:F:\python\Anaconda3\Lib\site-packages\flask_bootstrap\templates\bootstrap

這個模板利用Jinja2 的模板繼承機制,讓程序擴展一個具有基本頁面結構的基模板,其中就有用來
引入Bootstrap 的元素。

  • Jinja2 中的extends 指令從Flask-Bootstrap 中導入bootstrap/base.html, 從而實現模板繼承。
  • Flask-Bootstrap 中的基模板提供了一個網頁框架,引入了Bootstrap 中的所有CSS 和JavaScript 文件。
  • 基模板中定義了可在衍生模板中重定義的塊。block 和endblock 指令定義的塊中的內容可添加到基模板中。

(4) 導航條鏈接
(5) 警告框鏈接
4.Flask-Bootstrap自定義模板塊
Flask-Bootstrap 的base.html 模板還定義了很多其他塊,都可在衍生模板中使用,下表列出了所有可用的塊:
在這裏插入圖片描述
在這裏插入圖片描述
5.Flask-Bootstrap自定義模板塊的繼承實現
上表中的很多塊都是Flask-Bootstrap 自用的,如果直接重定義可能會導致一些問題。例如,Bootstrap 所需的文件在styles 和scripts 塊中聲明。**如果程序需要向已經有內容的塊中添加新內容,**必須使用Jinja2 提供的super() 函數。例如,如果要在衍生模板中添加新的JavaScript 文件,需要這麼定義scripts 塊:

{#鏈接我們自己寫的css ,super() :先去執行父類base.html的css,在執行<link>的自己寫的 css#}
{% block styles %}
{{ super()}}

<link rel="stylesheet" href="../static/css/main.css">
{% endblock %}

案例
繼承有公共樣式的html模板+實現那自己的樣式
基模板爲bootstrap/base.html,再定義一個繼承基模板的子模板base.html,其中子模版繼承基模板的樣式並填充導航欄部分,再對於標題挖坑。index.html等文件繼承子模板並對於標題填坑,以及基模板的content內容填坑。
run.py

from flask import Flask, render_template, flash
from flask_bootstrap import  Bootstrap


app = Flask(__name__)
app.config['SECRET_KEY'] = 'WESTOS'
bootstrap = Bootstrap(app) #初始化Bootstrap並與app關聯起來
@app.route('/')
def index():
    flash('login success')
    return  render_template('index.html')

@app.route('/bbs/')
def bbs():
    return  render_template('bbs.html')


@app.route('/blog/')
def blog():
    return  render_template('blog.html')

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

base.html
這裏base.html繼承了bootstrap/base.html

{% extends 'bootstrap/base.html' %}

{% block title%}

西部開源-{% block subtitle %} {% endblock %}
{% endblock %}

{#鏈接我們自己寫的css ,super() :先去執行父類base.html的css,在執行<link>的自己寫的 css#}
{% block styles %}
{{ super()}}

<link rel="stylesheet" href="../static/css/main.css">
{% endblock %}


{% block navbar %}
<nav class="navbar navbar-inverse">  <!--navbar-inverse 導航欄黑色-->
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">Brand</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
                <li><a href="#">Link</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Dropdown <span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="#">Action</a></li>
                        <li><a href="#">Another action</a></li>
                        <li><a href="#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">Separated link</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">One more separated link</a></li>
                    </ul>
                </li>
            </ul>
            <form class="navbar-form navbar-left">
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="Search">
                </div>
                <button type="submit" class="btn btn-default">Submit</button>
            </form>
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#">Link</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Dropdown <span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="#">Action</a></li>
                        <li><a href="#">Another action</a></li>
                        <li><a href="#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">Separated link</a></li>
                    </ul>
                </li>
            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>


{% for message in get_flashed_messages() %}

<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>
    <strong>Warning!</strong> {{ message }}
</div>

{% endfor %}


<p class="test">你好</p>

{% endblock %}

index.html
繼承base.html

{%  extends 'base.html' %}

{% block subtitle %}
主頁
{% endblock %}

{% block content %}
主頁
{% endblock %}

bbs.html

{% extends 'base.html' %}

{% block subtitle %}
論壇
{% endblock %}
{% block content %}
<h1>bbs</h1>

{% endblock %}

blog.html

{% extends 'base.html' %}
{% block subtitle %}

博客
{% endblock %}

{% block content %}
<h1>blog</h1>

{% endblock %}

main.css

.test{
    color: green;
    font-size: 32px;
}

運行run.py
導航欄設置成功
警告組設置成功,可以點擊× 關閉警告
實現標題 “西部開源-主頁”

在這裏插入圖片描述

二、Flask 集成郵件發送

1.爲什麼需要使用Flask-Mail組件?
在我們開發完web系統後,一些特定的事件發生時,系統要自動發送相關郵件至管理員,運維人員和其他相關人員。
python標準庫中的smtplib包也可以用在Flask程序中發送郵,但包裝了smtplib的flask-mail擴展能更好地
和Flask集成。
2.如何使用flask-mail擴展發送郵件?
安裝flask-mail擴展

pip install -i https://pypi.douban.com/simple flask-mail

3.項目案例:基於flask-mail 發送郵件
(1)發送郵件的時候需要設置什麼?

  • 發件人賬戶
  • 密碼
  • 收件人
  • 郵件標題
  • 郵件正文
  • QQ郵件服務器的域名或者IP

(2)配置信息設置
由於代碼中發件人賬戶的密碼不輸入真正的密碼而是服務器的授權碼,因此QQ服務器爲例來展示如何獲取授權碼。
可以在網上搜flask發送郵件的配置信息有哪些
發郵件需要用到qq服務器,那麼qq服務器怎麼設置?
在這裏插入圖片描述
在這裏插入圖片描述

(3)發送郵件準備工作
開啓POP3/SMTP服務:
在這裏插入圖片描述
發送短信,得到授權碼:tgoxgaysrbhlgeij
在這裏插入圖片描述
(4)詳細代碼

from flask_mail import Mail, Message
from flask import Flask, render_template, request, flash, redirect

app = Flask(__name__)
# 獲取配置文件中的配置信息;
app.config['MAIL_SERVER']='smtp.qq.com'
app.config['MAIL_PORT']=465
app.config['MAIL_USE_SSL']=True
app.config['MAIL_USERNAME']='1104213995'
app.config['MAIL_PASSWORD']='tgoxgaysrbhlgeij'
# 初始化mail對象, 一定要先配置郵件信息;
mail = Mail(app)

# def send_mail(to, subject, filename, **kwargs):
def send_mail(to, subject, info):
    """

    :param to: 收件人
    :param subject: 郵件主題
    :param filename: 郵件正文對應的html名稱
    :param kwargs: 關鍵字參數, 模版中需要的變量名
    :return:
    """

    msg = Message(subject=subject,
                  sender='[email protected]',
                  recipients=to,
                  )  #封裝成一個對象
    msg.body = info
    msg.html='<h1>郵件正文html內容</h1>'
    # msg.html = render_template(filename + '.html',  **kwargs)
    #安全上下文,本文用的是flask發送郵件的插件,所以要關聯一下flask app上下文,獲取裏面的變量在發送,就可以和項目結合起來。
    with app.app_context(): 
        mail.send(msg)

#當send_mail()函數綁定了html發送的內容時,這裏不管有沒有指定發送的info,都發送send_mail()函數中綁定的html內容。
send_mail(to=['[email protected]', '[email protected]'], subject="第2次測試",
          info="郵件測試正文") 

查看郵件:
在這裏插入圖片描述
4.項目案例:用戶註冊與郵件發送的結合
剛纔是發送郵件,一般發送郵件是和後臺結合起來的,使用路由和視圖函數。
最常用的場景:用戶在註冊的時候,註冊成功了,會給用戶發送一條郵件。
配置信息最好獨立放到一個文件config.py中
先寫一個基於flask-mail發送郵件的函數,然後訪問前端的註冊頁面,註冊成功,則調用發送郵件的函數來發送郵件

run.py


from flask_mail import Mail, Message
from flask import Flask, render_template, request, flash, redirect

app = Flask(__name__)
# 獲取配置文件中的配置信息;
app.config.from_pyfile('config.py')
def send_mail(to, subject, filename, **kwargs):
    """

    :param to: 收件人
    :param subject: 郵件主題
    :param filename: 郵件正文對應的html名稱
    :param kwargs: 關鍵字參數, 模版中需要的變量名
    :return:
    """
    # 初始化mail對象, 一定要先配置郵件信息,否則沒有報錯但也不發送郵件;
    mail = Mail(app)
    msg = Message(subject=subject,
                  sender='[email protected]',
                  recipients=to,
                  )  #封裝一個對象
    # msg.body = info
    #msg是Message()實例化出來的一個對象,裏面有一個html屬性,通過這個屬性指定要發送的html內容(爲了發送的內容格式好看)
    msg.html = render_template(filename + '.html',  **kwargs)
    #安全上下文,本文用的是flask發送郵件的插件,所以要關聯一下flask app上下文,獲取裏面的變量在發送,就可以和項目結合起來。
    with app.app_context():
        mail.send(msg)


# send_mail(to=['[email protected]', '[email protected]'], subject="第2次測試",
#           info="郵件測試正文")


@app.route('/register/', methods = ['POST', 'GET'])
def register():
    if request.method == 'GET':
        return  render_template('register.html')
    else:
        email = request.form.get('email')
        password = request.form.get('password')
        try:
            send_mail(to=[email], subject='註冊通知郵件', filename='registerok', username=email)
        except Exception as e:
            #前端通過get_flashed_messages()函數獲取這裏flask的閃現信息
            flash("註冊失敗")
            return redirect('/register/')
        else:
            flash("註冊成功")
            return redirect('/login/')

@app.route('/login/')
def login():
    return 'login'

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

config.py

MAIL_SERVER = 'smtp.qq.com'
# 指定端口, 默認25, 但qq郵箱默認爲 端口號465或587;
MAIL_PORT = 465

"""
由於QQ郵箱不支持非加密的協議,那麼使用加密協議, 分爲兩種加密協議,選擇其中之一即可
"""
MAIL_USE_SSL = True
MAIL_USERNAME = '1104213995'      #發件人用戶
# 此處的密碼並非郵箱登錄密碼, 而是開啓pop3
MAIL_PASSWORD = "tgoxgaysrbhlgeij"
# 調試模式打開
DEBUG = True
#在使用閃現信息時,幫我們保存在session裏面存儲時需要加密
SECRET_KEY = 'westos'

registerok.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1 style="color: green">註冊成功</h1>

尊敬的用戶<strong>{{ username }}</strong>:<br/>
    您已註冊網站西部開源成功, 請直接登錄網站.
</body>
</html>

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#獲取閃現信息#}
{% for message in get_flashed_messages() %}
<p style="color: red">{{message}}</p>
{% endfor %}

<form action="/register/" method="post">
    <input type="email" name="email" placeholder="email"><br/>
    <input type="password" name="password" placeholder="password"><br/>
    <input type="submit" value="註冊">

</form>
</body>
</html>

填寫註冊郵箱,此郵箱如果存在則註冊成功,不存在則註冊失敗
註冊成功則返回登陸界面,併發送一條郵件給[email protected]
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

三、Flask - wtf表單操作與用戶登陸結合

1.Flask的 WTForms 擴展(Flask-WTF )
Form表單,在Web應用中無處不在。比如: 用戶登錄表單, 用戶註冊表單。

  • 所有的表單項都有共性,比如有文字輸入框,單選框,密碼輸入框等;
  • 表單的驗證也有共性,比如有非空驗證,長度限制,類型驗證等。

如果有個框架,能把這些共性抽象出來,那就能大量簡化我們的工作。Python的 WTForms 就提供了這些功能,這裏我們就要結合Flask的 WTForms 擴展, Flask-WTF ,來介紹如何在Web應用中製作表單。
Flask-wtf 安裝:

pip install -i https://pypi.douban.com/simple flask-wtf

2.一個簡單的表單
(1)表單文件
在這裏插入圖片描述
(2)常見的表單域類型
在這裏插入圖片描述
在這裏插入圖片描述
(3)常見驗證規則

在這裏插入圖片描述
(4)視圖函數文件
在這裏插入圖片描述

(5)驗證數據
點擊了表單上的提交按鈕時, form.validate_on_submit() 判斷會做下面兩件事情:

  • 通過 is_submitted() 通過判斷HTTP方法來確認是否提交了表單
  • 通過 WTForms 提供的 validate() 來驗證表單數據

當validate()驗證未通過時,會在表單字段下面顯示我們傳進去的錯誤提示(例如message= u’郵
箱不能爲空’)。

(6)獲取數據
form.data是一個字典例如:
form.data {‘email’: ‘[email protected]’, ‘username’: ‘hello’}
可以通過form.email.data獲取email對應的value值。 可以通過form.username.data獲取’hello’

驗證通過後,使用 form.email.data 來獲得數據,

form.email.data

WTForms 提供的靜態方法.data返回一個以字段名(field name)和字段值(field value)作爲鍵
值對的字典。

form.data['email']

(7)自定義驗證

在這裏插入圖片描述
3.案例:Flask-wtf表單操作與用戶登陸結合
(1)案例:Flask-wtf表單操作與用戶登陸結合
寫好登陸表單函數class LoginForm(FlaskForm):和視圖函數、最終和前端頁面結合起來
form.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, SelectField, SelectMultipleField
from wtforms.validators import DataRequired, Length, Email, EqualTo, Regexp, ValidationError


class LoginForm(FlaskForm):
    email = StringField(label="電子郵箱",
                        validators=[
                            DataRequired(message='郵箱不能爲空'),
                            Length(1, 15, message="長度不符合條件"),
                            Email(message='請輸入有效的郵箱地址,比如:[email protected]')
                        ])
    password = PasswordField('密碼',
                             validators=[
                                 DataRequired(message=u'密碼不能爲空')])
    submit = SubmitField(u'登錄')

views.py

業務邏輯文件。
定義login()函數中,實例化表單對象,先返回login.html頁面,填寫email和password,並把form傳入,驗證通過後,獲取email和password


from flask import  Flask, request, render_template, flash
from forms import  LoginForm, RegisterForm

app = Flask(__name__)
app.config.from_pyfile('config.py')

@app.route('/login/', methods = ['GET', 'POST'])
def login():
    # 1. 實例化表單對象
    form = LoginForm()
    # 1). 是否爲post提交表單信息;
    # 2). 是否通過驗證函數?
    if form.validate_on_submit():
        # 獲取表單的內容
        email = form.email.data
        password = form.password.data
        if email =='[email protected]' and password=='westos':
            return  '登錄成功'
        else:
            return  "登錄失敗"
    else:
        return  render_template('login.html', form=form)

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

config.py

SECRET_KEY = 'WESTOS'

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/login/" method="post">
<!--隱藏起來的標籤,爲了表單填寫數據的安全-->
    {{ form.hidden_tag() }}
    {{form.email.label }} {{ form.email() }} {{ form.email.errors }}
    {{form.password.label }} {{ form.password() }} {{ form.password.errors }}
    {{ form.submit() }}

</form>
</body>
</html>

login.html還可以一句話實現好看的html登錄頁面

<!--導入Bootstrap的基模板, 自動加載css樣式和js動效-->
{% extends 'bootstrap/base.html' %}
<!--導入html代碼, 並起別名-->
{% import 'bootstrap/wtf.html'  as wtf %}


{%  block title %}
登錄
{% endblock %}


{% block content %}
<div style="width:70%; margin: 0 auto" >

    <h1>用戶登錄</h1>
    <hr/>
{#    根據form對象,快速生成表單的html#}
{{ wtf.quick_form(form) }}
    </div>

{% endblock %}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章