從零開始用 Flask 搭建一個網站(一) 介紹瞭如何搭建 Python 環境,以及 Flask 應用基本項目結構。咱們要搭建的網站是管理第三方集成的控制檯,相似於 Slack。 本篇主要講解數據如何在 Flask 應用中流動,其它的框架基本上也是大同小異。html
數據庫python
既然是數據的流動,首先要創建起存取數據的地方,也就是數據庫了(這裏是指關係型數據庫,NoSQL 不在這討論)。第一節中咱們使用了 Flask-SQLAlchemy 管理數據庫,在 Flask-SQLAlchemy 中,數據庫使用 URL 指定,最流行的數據庫 URL 格式以下:git
在 config.py 中咱們已經指定了數據庫 URL,若是使用雲平臺部署程序,直接將生成的數據庫 URL 寫到 config.py 中 SQLALCHEMY_DATABASE_URI 便可。這裏咱們使用的是 SQLite 數據庫。Flask-SQLAlchemy 採用數據庫抽象層來操做數據庫,也稱爲對象關係映射(Object-Relational Mapper, ORM),在用戶不知不覺的狀況下把高層的面向對象操做轉換成低層的數據庫指令,所以易用性好。咱們已經在 app/__init__.py 中實例化了 SQLAlchemy 類:github
app/__init__.pysql
from flask_sqlalchemy import SQLAlchemy ... db = SQLAlchemy() ...
定義模型shell
模型類能夠理解爲數據庫中的一張表,Flask-SQLAlchemy 提供了一個基類和一系列輔助類和函數來讓咱們定義模型的結構。咱們直接在 app 文件夾下建立一個 models.py 文件。鑑於每一個網站需求都不同,所存的數據也不一樣,但本質上是大同小異的。這裏以筆者網站需求爲例,須要建立 Developer,Integration 和 Channel 三個表。數據庫
app/models.py 部分代碼flask
from flask import current_app from app import db class Developer(db.Model): __tablename__ = 'developers' id = db.Column(db.Integer, primary_key=True) dev_key = db.Column(db.String(40), unique=True, index=True) platform = db.Column(db.String(50)) platform_id = db.Column(db.String(40), unique=True) username = db.Column(db.String(150), index=True) integrations = db.relationship('Integration', backref='developer') channels = db.relationship('Channel', backref='developer') class Integration(db.Model): __tablename__ = 'integrations' id = db.Column(db.Integer, primary_key=True) integration_id = db.Column(db.String(40), unique=True) name = db.Column(db.String(100)) description = db.Column(db.String(150)) icon = db.Column(db.String(150)) channel = db.Column(db.String(150)) token = db.Column(db.String(150)) developer_id = db.Column(db.Integer, db.ForeignKey('developers.id')) class Channel(db.Model): __tablename__ = 'channels' id = db.Column(db.Integer, primary_key=True) developer_id = db.Column(db.Integer, db.ForeignKey('developers.id')) channel = db.Column(db.String(150)) def __repr__(self): return '<Channel %r>' % self.channel
上面的每一個 Class 都繼承了 Model 類,所以每一個類在數據庫中都體現爲一張表,表名用 tablename 表示,通常用複數形式。這裏主要講一下一對多的關係。能夠看到上面 Developer 和 Integration 及 Channel 都有一個一對多的關係,一個用戶能夠有多個集成及多個頻道。 看到這兩句:bootstrap
integrations = db.relationship('Integration', backref='developer') developer_id = db.Column(db.Integer, db.ForeignKey('developers.id'))
第一句代表添加到 Developer 表的 integrations 屬性表示這個關係的面向對象視角,對於一個 Developer 實例,integrations 屬性將返回與 Developer 相關的全部 Integration,db.relationship() 第一個參數代表關係的另外一端是哪一個模型,backref 參數向 Integration 添加一個 developer 屬性,從而定義反向關係。第二句是在 Integration 表中建立一個 developer_id 字段,這個字段被定義爲外鍵,就是這個外鍵創建起了關係。傳給 db.ForeignKey() 的參數 'developers.id' 代表這列的值是 developers 表中行的 id 值。另外,__repr__() 方法返回一個具備可讀性的字符串表示模型,能夠在調加粗文字試和測試時使用。下面咱們就在命令行中操做一下數據庫。
首先執行:segmentfault
//建立 migrations 文件夾及相關文件 python manage.py db init
而後執行 :
//自動建立遷移腳本 python manage.py db migrate //建立數據表或者升級到最新版本 python manage.py db upgrade
之後模型類有改動,好比刪除或添加列,都要執行這兩個命令,更新數據庫表。如今在項目目錄下應該自動生成了名爲 dev 的數據庫。
接下來執行以下命令進入 Python Shell:
python manage.py shell
建立表
使用 db.create_all() 就能夠根據模型類建立表。如圖:
使用 db.drop_all() 方法就能夠刪除全部的表,可是這種方式比較粗暴,全部的數據也一同銷燬了。
插入行
如下命令在數據庫表中插入了一條數據:
經過數據庫會話 db.session 來管理對數據庫所作的改動,在準備把對象寫入數據庫以前,首先要添加到會話中,而後用 commit() 方法提交會話。接下來咱們繼續插入一條 Integration 數據:
>>>from app.models import Integration,Channel >>>integration = Integration(integration_id='i0001',name='github',description='first >>>application',channel='github_event',developer=developer) >>> db.session.add(integration) >>> db.session.commit()
注意上面的 developer 屬性,正是咱們在 models.py 中 Developer 模型中定義的一對多關係 integrations 屬性的 backref 值, 所謂的反向關係即指在 Integration 表中每條數據都有一個 developer 屬性指向 Developer 表中的某條數據,這是一對多關係的高級表示。如今能夠用 developer.integrations 來查看該 developer 擁有的哪些集成,運行截圖以下:
修改行
在提交數據庫會話以前,改變對象的某個屬性而後再提交便可更新行數據。如:
>>> developer.username = 'lisi' >>> db.session.add(developer) >>> db.session.commit()
運行截圖:
刪除行
調用 db.session.delete() 方法便可刪除行:
>>>db.session.delete(developer) >>>db.session.commit()
查詢行
Flask-SQLAlchemy 爲每一個模型提供了 query 對象,最基本的查詢是返回表中的全部記錄:
>>>Developer.query.all()
使用過濾器能夠進行更精確的查詢:
>>>Developer.query.filter_by(platform='qq').all()
若是你退出了 shell 會話,前面建立的對象就不會以 Python 對象的形式存在,而是做爲各自數據庫表中的行。這時須要重數據庫中讀取行,再從新建立 Python 對象,如:
>>> new_developer = Developer.query.filter_by(dev_key=12345).first()
注意上面的 first() 方法,若是不加上,將返回一個 BaseQuery 對象,這樣就不能直接用 new_developer 來訪問它的屬性值。
在視圖函數中操做數據庫
上面介紹的全部數據庫操做能夠直接在視圖函數中進行。假設咱們要作一個簡陋的註冊功能,下面咱們就來看看如何從網頁中獲取數據並保存在數據庫中。咱們先定義一個用戶模型:
app/models.py
class User(db.model): __tablename__ = 'users' id = db.column(db.Integer, primary_key=True) username = db.column(db.String(50), unique=True) password = db.column(db.String(100)) def __repr__(self): return '<User %r>' % self.username
而後在 main 文件夾下建立一個 forms.py 文件。
app/main/forms.py
from flask_wtf import Form from wtforms import StringField, SubmitField, PasswordField from wtforms.validators import DataRequired class UserForm(Form): username = StringField('Input your username', validators=[DataRequired()]) password = PasswordField('Input your password', validators=[DataRequired()]) submit = SubmitField('Submit')
咱們使用了 flask-wtf 擴展(pip install flask-wtf)來處理表單。
而後咱們用在 index 頁面中顯示這個表單。
index.html
{% extends "bootstrap/base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}註冊{% endblock %} {% block content %} {% for message in get_flashed_messages() %} <div class="alert alert-warning"> <button type="button" class="close" data-dismiss="alert">×</button> {{ message }} </div> {% endfor %} <div id="form"> <div class="col-md-4"> {{ wtf.quick_form(form) }} </div> </div> {% endblock %}
如今回到 views.py 中,在咱們的視圖函數中做以下改動:
app/main/views.py
... from .forms import UserForm from ..models import User from app import db @main.route('/', methods=['GET', 'POST']) def signin(): form = UserForm() if form is None: flash('Should input username and password') elif form.validate_on_submit(): user = User(username=form.username.data, password=form.password.data) db.session.add(user) try: db.session.commit() flash('User created !') except: db.session.rollback() flash('User create failed') return render_template('index.html', form=form)
接下來咱們運行一下這個小試驗:
python manage.py runserver
總結
本節咱們介紹了在 Flask 中是如何使用 Flask-SQLAlchemy 、Flask-Migrate來管理數據庫,而且示範了數據從網頁儲存到數據庫的過程,這只是最基礎的部分,下一節咱們將探索如何在網頁上發送請求而且獲得數據,以及如何在頁面之間傳遞數據。