源代碼: https://github.com/ltoddy/flask-tutorial
技術交流群:630398887(歡迎一起吹牛)
用到的數據庫是sqlite,這個數據庫不需要安裝,只要你電腦能運行C語言就行(是個能開機的電腦就可以……)。
安裝:
pip install flask-sqlalchemy
或者通過pycharm內置的pip安裝
這里說一下數據庫URL(待會要用到)。就是說阿,如果你要鏈接數據庫,得先告訴程序數據庫在哪,無論是local的或者remote的。URL就是那個數據庫的位置。
數據庫引擎 | URL |
---|---|
SQLite(Unix) | sqlite:////absolute/path/to/database |
SQLite(Windows) | sqlite:///c:/absolute/path/to/database |
不同的系統對于SQLite的URL是有一點不同的,我說一下原因,在Unix系統家族中,有一個根目錄"/",Unix系統是不分盤符的,也就是沒有C盤,D盤之類的,所有東西都在根目錄之下。而windows系統呢是分盤符的,比如你有東西在C盤,那么對于C盤來說,它的根目錄也就是c:/所以說,對于這兩個系統數據庫URL的切換,只需要'/'與'c:/'互相轉換一下就好了。
配置數據庫:
from flask_sqlalchemy import SQLAlchemy
import os
basedir = os.path.abspath(os.path.dirname(__file__))
# 我們要把數據庫放在當下的文件夾,這個basedir就是當下文件夾的絕對路徑
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + \
os.path.join(basedir, 'data.sqlite')
# 這里注意看,寫的是URI(統一資源標識符)
app.config['SQLALCHEMY_COMMIT_TEARDOWN'] = True
# SQLALCHEMY_COMMIT_TEARDOWN 因為數據庫每次有變動的時候,數據改變,但不會自動的去改變數據庫里面的數據,
# 只有你去手動提交,告訴數據庫要改變數據的時候才會改變,這里配置這個代表著,不需要你手動的去提交了,自動幫你提交了。
# 待會會有演示
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
簡單說一下數據庫:
正規點的定義就是:數據庫是長期存儲在計算機內,大量有組織可共享的數據的集合。
簡單點就是,比如你有一個database(數據庫),數據庫中有很多表格,就像excel那樣子。
表格中有每一列的名字(字段),用來標記每一列是存的什么信息。就這么簡單,當然數據還會有些特殊的屬性,比如primary key, unique, not null等等。
OK,我們來定義一下我們的表格。這個項目為了簡單,只設立一個User表。用來之后的注冊用的。
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
# 如果你學過數據庫的話就知道我們一般通過id來作為主鍵,來找到對應的信息的,通過id來實現唯一性
name = db.Column(db.String(64), unique=True)
下面將有一堆知識點,沒空看的話就跳過去好了,等遇到了再來查看。
我復制的,太多了手打得類似我。
常見的SQLALCHEMY列類型
類型名稱 | python類型 | 描述 |
---|---|---|
Integer | int | 常規整形,通常為32位 |
SmallInteger | int | 短整形,通常為16位 |
BigInteger | int或long | 精度不受限整形 |
Float | float | 浮點數 |
Numeric | decimal.Decimal | 定點數 |
String | str | 可變長度字符串 |
Text | str | 可變長度字符串,適合大量文本 |
Unicode | unicode | 可變長度Unicode字符串 |
Boolean | bool | 布爾型 |
Date | datetime.date | 日期類型 |
Time | datetime.time | 時間類型 |
Interval | datetime.timedelta | 時間間隔 |
Enum | str | 字符列表 |
PickleType | 任意Python對象 | 自動Pickle序列化 |
LargeBinary | str | 二進制 |
常見的SQLALCHEMY列選項
可選參數 | 描述 |
---|---|
primary_key | 如果設置為True,則為該列表的主鍵 |
unique | 如果設置為True,該列不允許相同值 |
index | 如果設置為True,為該列創建索引,查詢效率會更高 |
nullable | 如果設置為True,該列允許為空。如果設置為False,該列不允許空值 |
default | 定義該列的默認值 |
數據庫操作
創建表
python blog.py shell
>>> from hello import db
>>> db.create_all()
刪除表
db.drop_all()
插入行
#創建對象,模型的構造函數接受的參數是使用關鍵字參數指定的模型屬性初始值。
admin_role = Role(name='Admin')
user_role = Role(name='User')
user_susan = User(username='susan', role=user_role)#role 屬性也可使用,雖然它不是真正的數據庫列,但卻是一對多關系的高級表示。
user_john = User(username='john', role=admin_role)
#這些新建對象的 id 屬性并沒有明確設定,因為主鍵是由 Flask-SQLAlchemy 管理的。
print(admin_role.id)#None
#通過數據庫會話管理對數據庫所做的改動,在 Flask-SQLAlchemy 中,會話由 db.session 表示。
##首先,將對象添加到會話中
db.session.add(admin_role)
db.session.add(user_role)
db.session.add(user_susan)
db.session.add(user_john)
#簡寫:db.session.add_all([admin_role, user_role, user_john, user_susan])
##通過提交會話(事務),將對象寫入數據庫
db.session.commit()
修改行
admin_role.name = 'Administrator'
db.session.add(admin_role)
session.commit()
刪除行
db.session.delete(mod_role)
session.commit()
查詢行
查詢全部。Role.query.all()
條件查詢(使用過濾器)。User.query.filter_by(role=user_role).all()
user_role = Role.query.filter_by(name='User').first()#filter_by() 等過濾器在 query 對象上調用,返回一個更精確的 query 對象。
常用過濾器
過濾器 | 說 明 |
---|---|
filter() | 把過濾器添加到原查詢上,返回一個新查詢 |
filter_by() | 把等值過濾器添加到原查詢上,返回一個新查詢 |
limit() | 使用指定的值限制原查詢返回的結果數量,返回一個新查詢 |
offset() | 偏移原查詢返回的結果,返回一個新查詢 |
order_by() | 根據指定條件對原查詢結果進行排序,返回一個新查詢 |
group_by() | 根據指定條件對原查詢結果進行分組,返回一個新查詢 |
最常使用的SQLAlchemy查詢執行函數
方 法 | 說 明 |
---|---|
all() | 以列表形式返回查詢的所有結果 |
first() | 返回查詢的第一個結果,如果沒有結果,則返回 None |
first_or_404() | 返回查詢的第一個結果,如果沒有結果,則終止請求,返回 404 錯誤響應 |
get() | 返回指定主鍵對應的行,如果沒有對應的行,則返回 None |
get_or_404() | 返回指定主鍵對應的行,如果沒找到指定的主鍵,則終止請求,返回 404 錯誤響應 |
count() | 返回查詢結果的數量 |
paginate() | 返回一個 Paginate 對象,它包含指定范圍內的結果 |
OK,知識點到此為止。
我們來操作一下數據庫:
更改這個路由
@app.route('/', methods=['GET', 'POST'])
def index():
代碼如下:
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(name=form.name.data)
if user is None:
user = User(name=form.name.data)
db.session.add(user)
session['known'] = False
else:
session['known'] = True
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html',
form=form, name=session.get('name'),
known=session.get('known', False))
注意看 db.session.add(user)。
假設沒有app.config['SQLALCHEMY_COMMIT_TEARDOWN'] = True
這行代碼。
那么那行db.session.add(user)的后面需要加上db.session.commit()才可以把數據放到數據庫中。
對應的
/templates/index.html也要更改一下:
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block page_content %}
<div class="page-header">
<h1>Hello {% if name %}{{ name }}{% else %}stranger!{% endif %}</h1>
{% if not known %}
<p>Nice to meet you!</p>
{% else %}
<p>Happy to see you again!</p>
{% endif %}
</div>
{{ wtf.quick_form(form) }}
{% endblock %}
說一下,如果你要運行項目,然后打開頁面可能會出現一些SQLAlchemy的異常,這個時候,首先去看一下
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + \
os.path.join(basedir, 'data.sqlite')
這個,我們關心的是最后data.sqlite這個文件是否存在。
如果你沒有發現這個文件的話,那么打開terminal(pycharm已經集成好了).
python3 blog.py shell
>>> from blog import *
>>> db # 這一行目的是看看db被添加進來了么。
<SQLAlchemy engine=sqlite:////home/me/PycharmProjects/blog/data.sqlite>
>>> db.drop_all()
>>> db.create_all()
這個樣子你就會看到data.sqlite出現在你的文件夾中了。