引言
之前跟著教程用Django寫過一個博客,不過都是看著抄调衰,能運行就下一章,沒學到啥∽在澹現(xiàn)在決定重新用flask寫個嚎莉,然后每次看完都記錄學到什么,慢可以沛豌,但不能寫出了個博客問你啥你都不知道
官方文檔的入門指南
Step 0:創(chuàng)建文件
教你怎么創(chuàng)建文件趋箩,我直接用pycharm自動生成了就直接跳過
Step 1:數(shù)據(jù)庫架構
創(chuàng)建個數(shù)據(jù)庫
drop table if exists entries;
create table entries (
id integer primary key autoincrement,
title text not null,
'text' text not null
);
其他都懂,為啥text
要有單引號加派?
Step 2:應用程序設置代碼
app = Flask(__name__) # create the application instance :)
app.config.from_object(__name__) # load config from this file , flaskr.py
# Load default config and override config from an environment variable
app.config.update(dict(
DATABASE=os.path.join(app.root_path, 'flaskr.db'),
SECRET_KEY='development key',
USERNAME='admin',
PASSWORD='default'
))
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
整個設置程序叫确,指南里說最好的辦法是把這些配置信息一起寫到一個.ini
或者.py
的文件里
Flask()
是創(chuàng)建一個應用程序
app.config.from_object
設置從哪里加載配置文件
app.config.update
是設置配置信息,F(xiàn)lask會找到配置信息里面大寫的參數(shù)進行初始化芍锦,其中
-
app.root_path
和os.path
是為了適應不同的操作系統(tǒng)的文件系統(tǒng) -
secret_key
是用來保護用戶端的session安全的
app.config.from_envvar
是表示用環(huán)境變量來設置需要加載的配置文件竹勉,因為開發(fā)中和上線時需要的配置文件是不一樣的(像是DEBUG
)所以可以通過在shell腳本中設置要配置的文件,在運行Flask娄琉,后面的silent
的意思是如果沒有給環(huán)境變量賦值不報錯
Step 3:像安裝包一樣的安裝flaskr
里面講了為了以后可以用pip install ***
的方式來安裝程序次乓,所以參照python打包指南里的方式來設計程序目錄吓歇。
/flaskr
/flaskr
__init__.py
/static
/templates
flaskr.py
schema.sql
setup.py
MANIFEST.in
里面新增了setup.py
,__init__.py
票腰,MANIFEST.in
setup.py
from setuptools import setup
setup(
name='flaskr',
packages=['flaskr'],
include_package_data=True,
install_requires=[
'flask',
],
)
MANIFEST.in
指定那些文件需要被包含
graft flaskr/templates
graft flaskr/static
include flaskr/schema.sql
文檔里說明的命令代表的內(nèi)容
命令 | 內(nèi)容 |
---|---|
include pat1 pat2 ... | include all files matching any of the listed patterns |
exclude pat1 pat2 ... | exclude all files matching any of the listed patterns |
recursive-include dir pat1 pat2 ... | include all files under dir matching any of the listed patterns |
recursive-exclude dir pat1 pat2 ... | exclude all files under dir matching any of the listed patterns |
global-include pat1 pat2 ... | include all files anywhere in the source tree matching — & any of the listed patterns |
global-exclude pat1 pat2 ... | exclude all files anywhere in the source tree matching — & any of the listed patterns |
prune dir | exclude all files under dir |
graft dir | include all files under dir |
init.py
from .flaskr import app
運行方式
export FLASK_APP=flaskr
export FLASK_DEBUG=true
flask run
windows下用set
來代替export
Step 4:數(shù)據(jù)庫連接
里面提到了倆個上下文(context)照瘾,一個application上下文和一個request上下文,我感覺context翻譯成語境好點丧慈,上下文看的一臉懵逼析命,對應這倆上下文有倆個關鍵字request
,g
來分別代表request和application
然后是創(chuàng)建數(shù)據(jù)庫連接的代碼
def get_db():
"""Opens a new database connection if there is none yet for the
current application context.
"""
if not hasattr(g, 'sqlite_db'):
g.sqlite_db = connect_db()
return g.sqlite_db
關閉連接
@app.teardown_appcontext
def close_db(error):
"""Closes the database again at the end of the request."""
if hasattr(g, 'sqlite_db'):
g.sqlite_db.close()
teardown_appcontext()
會在每次application 上下文摧毀時調(diào)用
application上下文是先于request上下文創(chuàng)建時創(chuàng)建逃默,后于request上下文結束時結束
Step 5:創(chuàng)建數(shù)據(jù)庫
通過在flask命令行里加入一個鉤子方法用來初始化數(shù)據(jù)庫
def init_db():
db = get_db()
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
@app.cli.command('initdb')
def initdb_command():
"""Initializes the database."""
init_db()
print('Initialized the database.')
app.cli.command()
裝飾器會在flask命令行里注冊一個新的initdb
命令鹃愤,當執(zhí)行這個命令后flask會自動創(chuàng)建一個application上下文,當執(zhí)行完方法里的代碼后再自己摧毀和釋放數(shù)據(jù)庫連接
open_resource()
是一個方便開發(fā)者的方法完域,可以直接定位項目中的資源文件夾位置
現(xiàn)在開始執(zhí)行初始化
set FLASK_APP=flaskr //這里文檔里沒寫所以運行時會提示沒有該命令
flask initdb
Initialized the database.
Step 6:視圖方法
主頁視圖
@app.route('/')
def show_entries():
db = get_db()
cur = db.execute('select title, text from entries order by id desc')
entries = cur.fetchall()
return render_template('show_entries.html', entries=entries)
添加新實體
@app.route('/add', methods=['POST'])
def add_entry():
if not session.get('logged_in'):
abort(401)
db = get_db()
db.execute('insert into entries (title, text) values (?, ?)',
[request.form['title'], request.form['text']])
db.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
abort()
發(fā)送錯誤代碼給WSGI應用
flask.flash(message, category=’message’)
Flashes a message to the next request. In order to remove the flashed message from the session and to display it to the user, the template has to call
不太懂软吐,說是閃爍消息,感覺想Android里面的toast吟税,但是感覺又是Android里面的廣播
例子的實現(xiàn)方式是想日志一樣凹耙,就是為了友好的人機交互
文檔里寫會發(fā)送信息到下個請求和重定向到show_entries
網(wǎng)頁上
登陸
@app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != app.config['USERNAME']:
error = 'Invalid username'
elif request.form['password'] != app.config['PASSWORD']:
error = 'Invalid password'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('show_entries'))
return render_template('login.html', error=error)
登出
@app.route('/logout')
def logout():
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))
Step 7:模板
layout.html
<!doctype html>
<title>Flaskr</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
<div class=page>
<h1>Flaskr</h1>
<div class=metanav>
{% if not session.logged_in %}
<a href="{{ url_for('login') }}">log in</a>
{% else %}
<a href="{{ url_for('logout') }}">log out</a>
{% endif %}
</div>
{% for message in get_flashed_messages() %}
<div class=flash>{{ message }}</div>
{% endfor %}
{% block body %}{% endblock %}
</div>
show_entries.html
{% extends "layout.html" %}
{% block body %}
{% if session.logged_in %}
<form action="{{ url_for('add_entry') }}" method=post class=add-entry>
<dl>
<dt>Title:
<dd><input type=text size=30 name=title>
<dt>Text:
<dd><textarea name=text rows=5 cols=40></textarea>
<dd><input type=submit value=Share>
</dl>
</form>
{% endif %}
<ul class=entries>
{% for entry in entries %}
<li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
{% else %}
<li><em>Unbelievable. No entries here so far</em>
{% endfor %}
</ul>
{% endblock %}
login.html
{% extends "layout.html" %}
{% block body %}
<h2>Login</h2>
{% if error %}<p class=error><strong>Error:</strong> {{ error }}{% endif %}
<form action="{{ url_for('login') }}" method=post>
<dl>
<dt>Username:
<dd><input type=text name=username>
<dt>Password:
<dd><input type=password name=password>
<dd><input type=submit value=Login>
</dl>
</form>
{% endblock %}
style.css
body { font-family: sans-serif; background: #eee; }
a, h1, h2 { color: #377ba8; }
h1, h2 { font-family: 'Georgia', serif; margin: 0; }
h1 { border-bottom: 2px solid #eee; }
h2 { font-size: 1.2em; }
.page { margin: 2em auto; width: 35em; border: 5px solid #ccc;
padding: 0.8em; background: white; }
.entries { list-style: none; margin: 0; padding: 0; }
.entries li { margin: 0.8em 1.2em; }
.entries li h2 { margin-left: -1em; }
.add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; }
.add-entry dl { font-weight: bold; }
.metanav { text-align: right; font-size: 0.8em; padding: 0.3em;
margin-bottom: 1em; background: #fafafa; }
.flash { background: #cee5F5; padding: 0.5em;
border: 1px solid #aacbe2; }
.error { background: #f0d6d6; padding: 0.5em; }
在這停頓
大概了解到了整個flask的基本運行方法