eb應(yīng)用程序的一個(gè)重要方面是為用戶提供一個(gè)用戶界面。 HTML提供了一個(gè)<form>標(biāo)簽,用于設(shè)計(jì)一個(gè)接口。 可以適當(dāng)使用表單的元素,如文本輸入,廣播,選擇等。
通過GET或POST方法將用戶輸入的數(shù)據(jù)以Http請求消息的形式提交給服務(wù)器端腳本。
服務(wù)器端腳本必須從http請求數(shù)據(jù)重新創(chuàng)建表單元素。 所以實(shí)際上,表單元素必須被定義兩次 - 一次是HTML,一次是服務(wù)器端腳本。使用HTML表單的另一個(gè)缺點(diǎn)是很難(如果不是不可能)動(dòng)態(tài)地呈現(xiàn)表單元素。 HTML本身無法驗(yàn)證用戶的輸入。
這就是WTForms,一個(gè)靈活的表單,渲染和驗(yàn)證庫來得方便的地方。 Flask-WTF擴(kuò)展為這個(gè)WTForms庫提供了一個(gè)簡單的接口。
使用Flask-WTF,可以在Python腳本中定義表單域并使用HTML模板來呈現(xiàn)它們。 也可以將驗(yàn)證應(yīng)用于WTF字段。
下面讓我們看看這個(gè)動(dòng)態(tài)生成HTML是如何工作的。
首先,需要安裝Flask-WTF擴(kuò)展。
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
pip install flask-WTF
已安裝的軟件包包含一個(gè)Form類,該類必須用作用戶定義表單的父級。WTforms包包含各種表單域的定義。下面列出了一些標(biāo)準(zhǔn)表單字段。
編號 | 標(biāo)準(zhǔn)表單字段 | 描述 |
1 | TextField | 表示<input type='text'> HTML表單元素 |
2 | BooleanField | 表示<input type='checkbox'> HTML表單元素 |
3 | DecimalField | 用小數(shù)顯示數(shù)字的文本字段 |
4 | IntegerField | 用于顯示整數(shù)的文本字段 |
5 | RadioField | 表示<input type='radio'>的HTML表單元素 |
6 | SelectField | 表示選擇表單元素 |
7 | TextAreaField | 表示<testarea> html表單元素 |
8 | PasswordField | 表示<input type='password'> HTML表單元素 |
9 | SubmitField | 表示<input type='submit'>表單元素 |
例如,可以設(shè)計(jì)一個(gè)包含文本字段的表單,如下所示 -
示例
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
from flask_wtf import Form
from wtforms import TextField
class ContactForm(Form):
name=TextField("Name Of Student")
除了name字段之外,還會(huì)自動(dòng)創(chuàng)建一個(gè)CSRF令牌的隱藏字段。 這是為了防止跨站請求偽造攻擊。
渲染時(shí),這將產(chǎn)生一個(gè)等效的HTML腳本,如下所示。
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
<input id="csrf_token" name="csrf_token" type="hidden" />
<label for="name">Name Of Student</label><br>
<input id="name" name="name" type="text" value="" />
用戶定義的表單類在Flask應(yīng)用程序中使用,表單使用模板呈現(xiàn)。
示例
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
from flask import Flask, render_template
from forms import ContactForm
app=Flask(__name__)
app.secret_key='development key'
@app.route('/contact')
def contact():
form=ContactForm()
return render_template('contact.html', form=form)
if __name__=='__main__':
app.run(debug=True)
WTForms包也包含驗(yàn)證器類,在驗(yàn)證表單域時(shí)非常有用。 以下列表顯示了常用的驗(yàn)證器。
編號 | 驗(yàn)證器類 | 描述 |
1 | DataRequired | 檢查輸入欄是否為空 |
2 | 檢查字段中的文本是否遵循電子郵件ID約定 | |
3 | IPAddress | 驗(yàn)證輸入字段中的IP地址 |
4 | Length | 驗(yàn)證輸入字段中字符串的長度是否在給定范圍內(nèi) |
5 | NumberRange | 在給定范圍內(nèi)的輸入字段中驗(yàn)證一個(gè)數(shù)字 |
6 | URL | 驗(yàn)證輸入字段中輸入的URL |
將聯(lián)系表單的name字段應(yīng)用'DataRequired'驗(yàn)證規(guī)則。
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
name=TextField("Name Of Student",[validators.Required("Please enter your name.")])
表單對象的validate()函數(shù)驗(yàn)證表單數(shù)據(jù),并在驗(yàn)證失敗時(shí)拋出驗(yàn)證錯(cuò)誤。 錯(cuò)誤消息被發(fā)送到模板。 在HTML模板中,錯(cuò)誤消息是動(dòng)態(tài)呈現(xiàn)的。
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
{% for message in form.name.errors %}
{{ message }}
{% endfor %}
以下示例演示了上面給出的概念。聯(lián)系人表單代碼如下( forms.py)。
示例
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
from flask_wtf import Form
from wtforms import TextField, IntegerField, TextAreaField, SubmitField, RadioField, SelectField
from wtforms import validators, ValidationError
class ContactForm(Form):
name=TextField("學(xué)生姓名",[validators.Required("Please enter your name.")])
Gender=RadioField('性別', choices=[('M','Male'),('F','Female')])
Address=TextAreaField("地址")
email=TextField("Email",[validators.Required("Please enter your email address."),
validators.Email("Please enter your email address.")])
Age=IntegerField("年齡")
language=SelectField('語言', choices=[('cpp', 'C++'), ('py', 'Python')])
submit=SubmitField("提交")
驗(yàn)證器應(yīng)用于名稱和電子郵件字段。下面給出的是Flask應(yīng)用程序腳本( formexample.py)。
示例
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
from flask import Flask, render_template, request, flash
from forms import ContactForm
app=Flask(__name__)
app.secret_key='development key'
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form=ContactForm()
if request.method=='POST':
if form.validate()==False:
flash('All fields are required.')
return render_template('contact.html', form=form)
else:
return render_template('success.html')
elif request.method=='GET':
return render_template('contact.html', form=form)
if __name__=='__main__':
app.run(debug=True)
模板的腳本( contact.html)如下所示 -
# Filename : example.py
# Copyright : 2020 By Nhooo
# Author by : www.cainiaojc.com
# Date : 2020-08-08
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Flask示例</title>
</head>
<body>
<h2 style="text-align: center;">聯(lián)系人表單</h2>
{% for message in form.name.errors %}
<div>{{ message }}</div>
{% endfor %}
{% for message in form.email.errors %}
<div>{{ message }}</div>
{% endfor %}
<form action="http://localhost:5000/contact" method=post>
<fieldset>
<legend>填寫項(xiàng)</legend>
{{ form.hidden_tag() }}
<div style=font-size:20px; font-weight:bold; margin-left:150px;>
{{ form.name.label }}<br>
{{ form.name }}
<br>
{{ form.Gender.label }} {{ form.Gender }}
{{ form.Address.label }}<br>
{{ form.Address }}
<br>
{{ form.email.label }}<br>
{{ form.email }}
<br>
{{ form.Age.label }}<br>
{{ form.Age }}
<br>
{{ form.language.label }}<br>
{{ form.language }}
<br>
{{ form.submit }}
</div>
</fieldset>
</form>
</body>
</html>
在Python shell中運(yùn)行 formexample.py,并訪問URL=> http://localhost:5000/contact 。 聯(lián)系人表單將顯示如下。
如果有錯(cuò)誤信息,頁面將如下所示 -
如果沒有錯(cuò)誤,將呈現(xiàn) success.html頁面的內(nèi)容,如下所示 -
xia仔ke:chaoxingit.com/4964/
獲取資源:上方URL獲取資源
Python Flask 全流程全棧項(xiàng)目實(shí)戰(zhàn)
在現(xiàn)代軟件開發(fā)領(lǐng)域中,全棧開發(fā)成為了一種越來越流行的趨勢。全棧開發(fā)工程師不僅能夠熟練應(yīng)對前端和后端開發(fā),還能夠處理數(shù)據(jù)庫設(shè)計(jì)和部署等各個(gè)環(huán)節(jié)。Python語言作為一種簡潔、易讀、易學(xué)的編程語言,被廣泛應(yīng)用于全棧開發(fā)中。而Flask作為Python語言中一款輕量級的web框架,也備受開發(fā)者的青睞。
在本文中,我們將介紹如何使用Python Flask完成一個(gè)全流程全棧項(xiàng)目實(shí)戰(zhàn)。首先,我們需要明確項(xiàng)目的需求和功能。假設(shè)我們要開發(fā)一個(gè)簡單的博客應(yīng)用,用戶可以注冊賬號、登錄、發(fā)表文章、評論等功能。接下來,我們將按照以下步驟展開開發(fā):
要搭建一個(gè)基于Python和Flask的Web應(yīng)用環(huán)境,你可以按照以下步驟操作:
1. 安裝Python
確保你的系統(tǒng)上已經(jīng)安裝了Python。你可以在終端或命令行中輸入 python --version 或者 python3 --version 來檢查Python的版本。
2. 創(chuàng)建虛擬環(huán)境
使用Python的venv模塊來創(chuàng)建一個(gè)虛擬環(huán)境,這將幫助你隔離項(xiàng)目依賴。
bash深色版本
python3 -m venv myflaskapp_env
source myflaskapp_env/bin/activate # 在Unix或Mac OS中
myflaskapp_env\Scripts\activate # 在Windows中
3. 安裝Flask和其他依賴
在激活的虛擬環(huán)境中,使用pip安裝Flask和其他可能需要的庫,例如SQLAlchemy(用于數(shù)據(jù)庫操作)和Flask-Migrate(用于數(shù)據(jù)庫遷移)。
bash深色版本
pip install flask flask-sqlalchemy flask-migrate
4. 創(chuàng)建Flask項(xiàng)目
在你喜歡的代碼編輯器中創(chuàng)建一個(gè)新的目錄作為項(xiàng)目根目錄,比如 myflaskapp。
bash深色版本
mkdir myflaskapp
cd myflaskapp
5. 初始化Flask應(yīng)用
在項(xiàng)目根目錄下創(chuàng)建一個(gè)名為 app.py 的文件,并添加以下代碼來初始化Flask應(yīng)用:
python深色版本
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='sqlite:///site.db' # 使用SQLite數(shù)據(jù)庫
db=SQLAlchemy(app)
migrate=Migrate(app, db)
if __name__=='__main__':
app.run(debug=True)
6. 配置數(shù)據(jù)庫
在上面的代碼中,我們配置了數(shù)據(jù)庫URI。你需要根據(jù)實(shí)際使用的數(shù)據(jù)庫類型和設(shè)置進(jìn)行修改。此外,你還可以創(chuàng)建一個(gè)單獨(dú)的配置文件,如 config.py,并在 app.py 中導(dǎo)入它。
7. 定義模型
在 models.py 文件中定義你的數(shù)據(jù)模型。例如:
python深色版本
class User(db.Model):
id=db.Column(db.Integer, primary_key=True)
username=db.Column(db.String(80), unique=True, nullable=False)
email=db.Column(db.String(120), unique=True, nullable=False)
8. 運(yùn)行Flask應(yīng)用
在你的虛擬環(huán)境中運(yùn)行Flask應(yīng)用:
bash深色版本
python app.py
這樣,你就有了一個(gè)基本的Flask應(yīng)用環(huán)境,可以開始構(gòu)建你的Web應(yīng)用了。記得在開發(fā)過程中,使用 deactivate 命令退出虛擬環(huán)境,以避免不必要的依賴沖突。
前端開發(fā)是Web應(yīng)用的重要組成部分,負(fù)責(zé)處理用戶界面的展示與交互。使用HTML、CSS和JavaScript(簡稱“前端三劍客”)是構(gòu)建前端的基本方式,而引入如Bootstrap這樣的前端框架可以極大地提升開發(fā)效率并保持界面的一致性和美觀性。以下是具體步驟:
1. HTML 結(jié)構(gòu)
HTML(HyperText Markup Language)用于定義網(wǎng)頁的基本結(jié)構(gòu)。在你的Flask應(yīng)用中,HTML文件通常放在 templates 目錄下。例如,創(chuàng)建一個(gè)基本的主頁模板 index.html:
html深色版本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Flask App</title>
<!-- 引入Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/ bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Welcome to My Flask App</h1>
<!-- 頁面內(nèi)容 -->
</div>
<!-- 引入Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery /3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js /1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2 /js/bootstrap.min.js"></script>
</body>
</html>
2. CSS 樣式
CSS(Cascading Style Sheets)用于美化HTML頁面。可以創(chuàng)建一個(gè) static/css/styles.css 文件來存放自定義樣式,并在HTML中引用它。Bootstrap提供了許多預(yù)定義的類,可以直接應(yīng)用于HTML元素以快速實(shí)現(xiàn)美觀的布局。
3. JavaScript 交互
JavaScript 是用來增加網(wǎng)頁動(dòng)態(tài)功能的語言。在 static/js 目錄下創(chuàng)建JavaScript文件,例如 main.js,并在HTML中引用。可以利用Bootstrap的JavaScript插件或者jQuery來簡化DOM操作和事件處理。
4. 使用Bootstrap
Bootstrap是一個(gè)流行的前端框架,提供了響應(yīng)式設(shè)計(jì)、預(yù)定義的組件和JavaScript插件。在上面的HTML示例中,我們通過CDN鏈接引入了Bootstrap的CSS和JS文件。你也可以下載Bootstrap并將其放在項(xiàng)目的靜態(tài)文件目錄中。
5. 集成到Flask
在Flask中,你可以使用 render_template 函數(shù)來渲染HTML模板。例如,在 app.py 中添加以下路由:
python深色版本
from flask import render_template
@app.route('/')
def index():
return render_template('index.html')
這樣,當(dāng)你訪問 / 路徑時(shí),F(xiàn)lask會(huì)渲染 templates/index.html 并顯示在瀏覽器中。
6. 開發(fā)和測試
在本地開發(fā)環(huán)境中,你可以使用現(xiàn)代瀏覽器的開發(fā)者工具來調(diào)試CSS和JavaScript,確保前端頁面按預(yù)期工作。
7. 響應(yīng)式設(shè)計(jì)
Bootstrap支持響應(yīng)式設(shè)計(jì),這意味著你的頁面在不同設(shè)備上(如手機(jī)和平板)都能良好顯示。確保在開發(fā)過程中測試不同屏幕尺寸的兼容性。
通過這些步驟,你可以創(chuàng)建一個(gè)既美觀又功能強(qiáng)大的前端界面,與后端的Flask應(yīng)用無縫集成。
在后端開發(fā)中,使用Flask來處理HTTP請求和數(shù)據(jù)庫操作是非常常見的做法。下面我將指導(dǎo)你如何實(shí)現(xiàn)用戶注冊、登錄、發(fā)布文章以及評論功能。
1. 用戶注冊與登錄
注冊功能
首先,你需要?jiǎng)?chuàng)建一個(gè)用戶模型,如果還沒有的話。假設(shè)你已經(jīng)有了一個(gè)User模型,現(xiàn)在讓我們創(chuàng)建一個(gè)注冊路由:
python深色版本
from flask import request, redirect, url_for
from werkzeug.security import generate_password_hash
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method=='POST':
username=request.form.get('username')
password=request.form.get('password')
hashed_password=generate_password_hash (password, method='sha256')
new_user=User(username=username, password=hashed_password)
db.session.add(new_user)
db.session.commit()
return redirect(url_for('login'))
return render_template('register.html')
登錄功能
登錄功能需要驗(yàn)證用戶的用戶名和密碼:
python深色版本
from flask_login import login_user
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method=='POST':
username=request.form.get('username')
password=request.form.get('password')
user=User.query.filter_by(username=username).first()
if user and user.check_password(password):
login_user(user)
return redirect(url_for('index'))
else:
flash('Invalid username or password')
return render_template('login.html')
2. 發(fā)布文章
為了實(shí)現(xiàn)文章的發(fā)布功能,你需要?jiǎng)?chuàng)建一個(gè)文章模型(如Article),并提供一個(gè)相應(yīng)的路由:
python深色版本
from flask_login import current_user
@app.route('/create-article', methods=['GET', 'POST'])
@login_required # 確保用戶已登錄
def create_article():
if request.method=='POST':
title=request.form.get('title')
content=request.form.get('content')
new_article=Article(title=title, content=content, author=current_user)
db.session.add(new_article)
db.session.commit()
return redirect(url_for('index'))
return render_template('create_article.html')
3. 評論功能
評論功能通常涉及到文章和評論之間的關(guān)系,你需要?jiǎng)?chuàng)建一個(gè)評論模型(如Comment)并與文章模型建立關(guān)聯(lián)。評論的路由可以如下所示:
python深色版本
@app.route('/article/<int:article_id>/comment', methods=['POST'])
@login_required
def add_comment(article_id):
article=Article.query.get_or_404(article_id)
comment_text=request.form.get('comment')
new_comment=Comment(text=comment_text, author=current_user, article=article)
db.session.add(new_comment)
db.session.commit()
return redirect(url_for('article_detail', article_id=article_id))
4. 數(shù)據(jù)庫操作
所有上述功能都需要與數(shù)據(jù)庫交互,包括讀取、插入、更新和刪除數(shù)據(jù)。使用SQLAlchemy ORM可以方便地進(jìn)行這些操作。
5. 安全性和認(rèn)證
確保在處理敏感信息時(shí),如用戶密碼,使用安全的方法進(jìn)行存儲(chǔ)(如bcrypt哈希)。同時(shí),使用Flask-Login庫管理用戶會(huì)話和權(quán)限。
以上是實(shí)現(xiàn)基本用戶管理、文章發(fā)布和評論功能的概覽。在實(shí)際開發(fā)中,你可能還需要考慮錯(cuò)誤處理、表單驗(yàn)證、分頁、搜索等功能。
通過以上步驟,我們可以完成一個(gè)簡單的全流程全棧項(xiàng)目實(shí)戰(zhàn)。在實(shí)際開發(fā)中,可以根據(jù)項(xiàng)目需求和規(guī)模來進(jìn)行適當(dāng)?shù)臄U(kuò)展和優(yōu)化。Python Flask作為一款優(yōu)秀的web框架,能夠幫助開發(fā)者快速高效地完成項(xiàng)目開發(fā),希望本文能對正在學(xué)習(xí)全棧開發(fā)的朋友們有所幫助。
文分享自眾成翻譯,介紹了一個(gè)將熱門前端技術(shù) Vue.js 與流行 Python 后端框架 Flask 結(jié)合的簡單示例。推薦有興趣采用類似技術(shù)棧的同學(xué)看看。
譯者:楓林
鏈接:http://www.zcfy.cc/article/4491
原文:https://codeburst.io/full-stack-single-page-application-with-vue-js-and-flask-b1e036315532
在本教程中,我將向大家展示如何使用前端的 Vue.js 單頁面應(yīng)用和后端的 Flask 進(jìn)行交互。
如果你只是想使用 Vue.js 庫和 Flask 模板基本上是沒什么問題的。但...好吧,其實(shí)還是有一個(gè)比較顯而易見的問題:跟 Vue.js 一樣,Jinji(模板引擎)也是使用雙大括號來渲染頁面,但已經(jīng)有一個(gè)很好的解決方案 在這里 了。
我想要一個(gè)跟上面方案有點(diǎn)不同的例子。如果我要一個(gè)用 Vue.js(使用單頁面組件,在 vue-router
開啟 HTML5 history 模式,還有使用其他一些非常棒的特性)框架的單頁面和 Flask 做后臺服務(wù)的應(yīng)用?應(yīng)該能按下面的要求工作:
Flask運(yùn)行的服務(wù)可以訪問 index.html
首頁和 Vue.js 應(yīng)用
在前端開發(fā)環(huán)境,使用 Webpack 和它提供的很多非常棒的功能
可以從前端的單頁面應(yīng)用訪問 Flask 的 API 接口
以 Node.js 服務(wù)運(yùn)行的前端開發(fā)環(huán)境同樣也可以訪問 API 接口
這看起來很有趣,不是嗎?那就讓我們開始吧。
你可以在github上查看所有的源代碼:
https://github.com/oleg-agapov/flask-vue-spa
我用 vue-cli 命令行工具搭建起 Vue.js 的基礎(chǔ)框架。如果你還沒有安裝,可以運(yùn)行:
$ npm install -g vue-cli
客戶端和后端代碼將會(huì)放到不同的文件夾下,初始化前端部分執(zhí)行如下操作:
$ mkdir flaskvue
$ cd flaskvue
$ vue init webpack frontend
以下是我通過安裝向?qū)У捻?xiàng)目設(shè)置:
Vue build — Runtime only (Vue 構(gòu)建的版本 - 運(yùn)行時(shí))
Install vue-router? — Yes (安裝 vue-router? - 是)
Use ESLint to lint your code? — Yes (使用 ESLint 校驗(yàn)?zāi)愕拇a? - 是)
Pick an ESLint preset — Standard (選擇 ESList 的預(yù)置版本 - 標(biāo)準(zhǔn))
Setup unit tests with Karma + Mocha? — No (使用 Karma + Mocha 設(shè)置單元測試? - 否)
Setup e2e tests with Nightwatch? — No (使用 Nightwatch 設(shè)置端到端測試? - 否)
下一步:
$ cd frontend
$ npm install
# after installation
$ npm run dev
現(xiàn)在你可以開始設(shè)置 Vue.js 應(yīng)用了。讓我們先來添加些頁面吧。
添加 Home.vue
和About.vue
到frontend/src/components
文件夾。像如下簡單添加些內(nèi)容:
// Home.vue
<template>
<div>
<p>Home page</p>
</div>
</template>
和
// About.vue
<template>
<div>
<p>About</p>
</div>
</template>
我們將在本地驗(yàn)證它們(通過地址欄訪問)。現(xiàn)在我們要改變 frontend/src/router/index.js
文件去一個(gè)個(gè)渲染我們的新組件:
import Vue from 'vue'
import Router from 'vue-router'
const routerOptions=[
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' }
]
const routes=routerOptions.map(route=> {
return {
...route,
component:=> import(`@/components/${route.component}.vue`)
}
})
Vue.use(Router)
export default new Router({
routes,
mode: 'history'
})
現(xiàn)在如果輸入 localhost:8080
和localhost:8080/about
你應(yīng)該看到相應(yīng)的頁面。
在我們構(gòu)建生成項(xiàng)目靜態(tài)資源前還需要修改它們的輸出路徑。在 frontend/config/index.js
找到下面的兩行
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
然后成改如下內(nèi)容
index: path.resolve(__dirname, '../../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../../dist'),
所以, 包含 html/css/js 靜態(tài)資源包的 /dist
文件夾和/frontend
在同一級目錄下。現(xiàn)在你可以運(yùn)行$ npm run build
去構(gòu)建項(xiàng)目了
Flask 后端,我將使用 3.6 版本的 python。在根目錄 /flaskvue
文件夾下為后端代碼和初始化虛擬環(huán)境創(chuàng)建新的子目錄:
$ mkdir backend
$ cd backend
$ virtualenv -p python3 venv
開啟虛擬環(huán)境執(zhí)行(mac系統(tǒng)):
$ source venv/bin/activate
在 Windows 上開啟請看這里 docs。
在虛擬環(huán)境中安裝 Flask 如下:
(venv) pip install Flask
現(xiàn)在讓我們開始寫 Flask 服務(wù)器端代碼。在根目錄下創(chuàng)建 run.py
文件:
(venv) cd ..
(venv) touch run.py
然后添加以下代碼到這個(gè)文件:
from flask import Flask, render_template
app=Flask(__name__,
static_folder="./dist/static",
template_folder="./dist")
@app.route('/')
def index:
return render_template("index.html")
上面的代碼和 Flask 入門教程 “Hello world” 上的代碼稍有不同。最主要的不同點(diǎn)在于我們詳細(xì)指明了前端的靜態(tài)和模板文件夾輸出到 /dist
文件夾。然后在根目錄下運(yùn)行 Flask 服務(wù)。
(venv) FLASK_APP=run.py FLASK_DEBUG=1 flask run
這將會(huì)在 localhost:5000
開啟一個(gè)后臺服務(wù)。FLASK_APP
指向服務(wù)啟動(dòng)文件,FLASK_DEBUG=1
將會(huì)以調(diào)試模式運(yùn)行。如果沒有錯(cuò)誤,你將會(huì)看到熟悉的首頁,這樣,服務(wù)器就成功運(yùn)行 Vue 應(yīng)用了。
與此同時(shí)如果你試圖訪問 /about
頁面將會(huì)出現(xiàn)一個(gè)錯(cuò)誤。Flask 會(huì)拋出一個(gè)找不到請求地址的錯(cuò)誤。實(shí)際上是因?yàn)樵?code>vue-router用了 HTML5 的 history 模式, 所以我們需要配置我們的后臺服務(wù)去重定向所有的路由都跳轉(zhuǎn)到index.html
上。這在 Flask 上可以很簡單做到。做如下修改:
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
return render_template("index.html")
現(xiàn)在地址 localhost:5000/about
將會(huì)重定向到index.html
和vue-router
將會(huì)在它自己內(nèi)部處理。
因?yàn)樵谖覀兊暮笈_服務(wù)里設(shè)置捕捉所有路由是非常困難的,所以我們用 Flask 捕捉 404 錯(cuò)誤會(huì)重定向 所有請求到index.html
(連同不存在的頁面)。在 Vue.js 應(yīng)用里處理未定義的路由。當(dāng)然,所有的工作均可在我們的路由文件設(shè)置。
在 frontend/src/router/index.js
增加一行:
const routerOptions=[
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' },
{ path: '*', component: 'NotFound' }
]
通配符 '*'
在vue-router
里的含義是以上路由定義之外的情況。現(xiàn)在我們需要在/components
文件夾新建NotFound.vue
文件。我簡單地創(chuàng)建它:
// NotFound.vue
<template>
<div>
<p>404 - Not Found</p>
</div>
</template>
現(xiàn)在 通過 npm run dev
重新啟動(dòng)前臺服務(wù)然后隨意輸入網(wǎng)址像localhost:8080/gljhewrgoh
。你應(yīng)該看到 “Not Found” 兩個(gè)單詞。
我的 Vue.js/Flask 教程的最后一個(gè)例子將在后端創(chuàng)建一個(gè) API 接口然后通過前端來調(diào)用它。我將創(chuàng)建一個(gè)隨機(jī)返回?cái)?shù)字1到100的簡單端口。
打開 run.py
新增如下代碼:
from flask import Flask, render_template, jsonify
from random import *
app=Flask(__name__,
static_folder="./dist/static",
template_folder="./dist")
@app.route('/api/random')
def random_number:
response={
'randomNumber': randint(1, 100)
}
return jsonify(response)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
return render_template("index.html")
我首先從 Flask 資源庫導(dǎo)入 random
庫和jsonify
函數(shù)。然后我增加一個(gè)返回 JSON 數(shù)據(jù)格式的新路由/api/random
, 如下:
{
"randomNumber": 36
}
你可以通過地址: localhost:5000/api/random
來測試這個(gè)路由。
到這里,服務(wù)端的工作已經(jīng)完成了。該到客戶端上場了。我將修改 Home.vue
組件來顯示我的隨機(jī)數(shù)字:
<template>
<div>
<p>Home page</p>
<p>Random number from backend: {{ randomNumber }}</p>
<button @click="getRandom">New random number</button>
</div>
</template>
<script>
export default {
data {
return {
randomNumber: 0
}
},
methods: {
getRandomInt (min, max) {
min=Math.ceil(min)
max=Math.floor(max)
return Math.floor(Math.random * (max - min + 1)) + min
},
getRandom {
this.randomNumber=this.getRandomInt(1, 100)
}
},
created {
this.getRandom
}
}
</script>
在這一步,我將在客戶端模擬隨機(jī)數(shù)的生成。所以,組件的工作過程如下:
初始變量 randomNumber
等于0
在 methods
部分,我們用getRandomInt(min, max)
函數(shù)從指定區(qū)間返回一個(gè)數(shù)字,getRandom
函數(shù)將調(diào)用上一個(gè)函數(shù)生成一個(gè)值賦給randomNumber
之后在組件被創(chuàng)建時(shí)調(diào)用 getRandom
方法給randomNumber
賦個(gè)初始數(shù)值
在按鈕點(diǎn)擊事件里,我們將觸發(fā) getRandom
方法去得到一個(gè)數(shù)值
現(xiàn)在,在首頁上你將看到由前端生成的隨機(jī)數(shù)。讓我們繼續(xù)來連接后端。
我將用 axios 庫來連接后端。它將允許我們創(chuàng)建能返回 Promise
對象的 HTTP 請求。我們先安裝它:
(venv) cd frontend
(venv) npm install --save axios
再次打開 Home.uve
,修改<script>
部分代碼:
import axios from 'axios'
methods: {
getRandom {
// this.randomNumber=this.getRandomInt(1, 100)
this.randomNumber=this.getRandomFromBackend
},
getRandomFromBackend {
const path=`[http://localhost:5000/api/random`](http://localhost:5000/api/random`)
axios.get(path)
.then(response=> {
this.randomNumber=response.data.randomNumber
})
.catch(error=> {
console.log(error)
})
}
}
在文件頂部,我們先導(dǎo)入 axios 庫。然后用 axios 去異步調(diào)用新方法 getRandonFromBackend
接收返回的結(jié)果。最后,getRandom
方法調(diào)用getRandomFromBackend
去獲取隨機(jī)值。
保存文件,打開瀏覽器,再次運(yùn)行前端開發(fā)服務(wù)器環(huán)境,刷新 localhost:8080
然后... 你應(yīng)該看到控制臺報(bào)了沒有隨機(jī)值的錯(cuò)誤。但不用擔(dān)心,一切正常運(yùn)行中。我們得到 cors 的錯(cuò)誤,它的意思是我們的 Flask 后臺 API 默認(rèn)不對其他的域名和端口(我們的例子運(yùn)行的是 Vue.js 應(yīng)用)開放。當(dāng)你用npm run build
生成包然后打開localhost:5000
(Flask 服務(wù))你會(huì)看到應(yīng)用正常運(yùn)行不再報(bào)錯(cuò)了。但如果每次在客戶端改了一點(diǎn)東西都要重新構(gòu)建包,顯然不是很方便。
Flask 的 CORS 插件允許我們?yōu)樵L問 API 創(chuàng)建規(guī)則。插件叫 flask-cors,我們先來安裝它:
(venv) pip install -U flask-cors
你可以通過閱讀文檔選擇更好的方法來在你的服務(wù)器上開啟 CORS。我這里將會(huì)用資源指定的方法應(yīng)用 {"origins": "*"}
去允許所有/api/*
下的路由(所以任何人都可以訪問/api
接口)。修改run.py
:
from flask_cors import CORS
app=Flask(__name__,
static_folder="./dist/static",
template_folder="./dist")
cors=CORS(app, resources={"/api/*": {"origins": "*"}})
改好之后,你就可以從前端的開發(fā)環(huán)境調(diào)用 Flask API 接口了。
太神奇了 ?!
現(xiàn)在你擁有了一個(gè)用你喜愛的技術(shù)完成的全棧應(yīng)用。
最后我想說說如何改進(jìn)這個(gè)方案。
首先,在你代碼里所有使用到的環(huán)境變量。主要是關(guān)于使用 FLASK_DEBUG
變量。我們在 CORS 設(shè)置中使用到它。例如,如果服務(wù)運(yùn)行在開發(fā)環(huán)境設(shè)置FLASK_DEBUG=1
你可以允許任何的請求源。如果不是,禁用 CORS 或者只允許可信源請求。
另外一個(gè)改進(jìn)是避免在客戶端硬編碼 API 路由。也許你需要思考為 API 接口創(chuàng)建映射表。所以當(dāng)你改變 API 路由,你所需要做的只是更新映射表。前端的調(diào)用接口將不需要改變。
還有個(gè)小建議 - 我通常同時(shí)開啟至少3個(gè)終端窗口:一個(gè)運(yùn)行 Flask,二個(gè)運(yùn)行 Vue.js(第一個(gè)運(yùn)行 Node.js 服務(wù),第二個(gè)用來做項(xiàng)目構(gòu)建打包)。
源代碼:https://github.com/oleg-agapov/flask-vue-spa
回復(fù)下方「關(guān)鍵詞」,獲取優(yōu)質(zhì)資源
回復(fù)關(guān)鍵詞「 pybook03」,立即獲取主頁君與小伙伴一起翻譯的《Think Python 2e》電子版
回復(fù)關(guān)鍵詞「pybooks02」,立即獲取 O'Reilly 出版社推出的免費(fèi) Python 相關(guān)電子書合集
回復(fù)關(guān)鍵詞「書單02」,立即獲取主頁君整理的 10 本 Python 入門書的電子版
印度小伙寫了套深度學(xué)習(xí)教程,Github上星標(biāo)已經(jīng)5000+
上百個(gè)數(shù)據(jù)文件合并,只能手動(dòng)復(fù)制粘貼?教你一招十秒搞定!
一個(gè)提升圖像識別準(zhǔn)確率的精妙技巧
一文讀懂:從 Python 打包到 CLI 工具
如何使用 Python 進(jìn)行時(shí)間序列預(yù)測?
美亞Kindle排名第一的Python 3入門書,火遍了整個(gè)編程圈
十分鐘搭建私有 Jupyter Notebook 服務(wù)器
使用 Python 制作屬于自己的 PDF 電子書
12步輕松搞定Python裝飾器
200 行代碼實(shí)現(xiàn) 2048 游戲
題圖:pexels,CC0 授權(quán)。
點(diǎn)擊閱讀原文,查看更多 Python 教程和資源。
*請認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。