一:關系型數據庫 mysql
Flask-SQLAlchemy管理關系型數據庫。
mysql數據庫引擎:url : mysql://username:passowrd@hostname/database
安裝相關依賴包:
pip install flask-sqlalchemy
pip install flask-mysqldb 如果使用mysql數據庫需要安裝這個依賴包
數據庫連接配置:
from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__) app.config["SQLALCHEMY_DATABASE"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest" # 配置數據庫的鏈接 app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True # 請求結束后自動提交數據庫的變動 app.config['SQLALCHEMY_ECHO'] = True # 執行后顯示原始sql語句 db = SQLAlchemy(app) @app.route("/user") def user(): pass if __name__ == '__main__': app.run()
二:數據庫模型 orm
object-relationship-map 對象關系映射,簡答說:就是通過創建實例對象==相當於在數據庫中映射了一張表。
from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__) app.config["SQLALCHEMY_DATABASE"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest" app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SQLALCHEMY_ECHO'] = True db = SQLAlchemy(app) @app.route("/user") def user(): pass # 定義對象 class Role(db.Model): # 類變量定義了數據庫中的表名。如果沒有指定,會已類的名稱小寫為表名,也就是role __tablename__ = "roles" id = db.Column(db.Integer,primary_key=True) # create table roles(id int(64) primary key, name varchar(64) unique); name = db.Column(db.String(64),unique=True) # desc roles; def __repr__(self): return "<Role %s>" % self.name class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True,index=True) def __repr__(self): return "<User %s>" % self.username if __name__ == '__main__': app.run()
外鍵和關聯的創建
# 定義對象 class Role(db.Model): # 類變量定義了數據庫中的表名。如果沒有指定,會已類的名稱小寫為表名,也就是role __tablename__ = "roles" id = db.Column(db.Integer,primary_key=True) name = db.Column(db.String(64),unique=True) us = db.relationship("User",backref="role") # us這個字段,關聯了User類(要寫類名):backref="role"表明User類中可以反向引用role對象。 def __repr__(self): return "<Role %s>" % self.name class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True,index=True) role_id = db.Column(db.Integer,db.ForeignKey("roles.id")) # role_id 是關聯了roles表的id字段。 def __repr__(self): return "<User %s>" % self.username
# 一對多的關系:一個role可以對應多個user用戶。
插入數據:
報錯:'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '
from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__) db = SQLAlchemy(app) # 錯誤一:db在app.config之后設置,應該為之前設置。 app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest" # 錯誤二:SQLALCHEMY_DATABASE_URI不是URL
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = False #SQLALCHEMY_COMMIT_ON_TEARDOWN 鍵,將其設為True時,每次請求結束后都會自動提交數據庫中的變動
app.config['SQLALCHEMY_ECHO'] = True
if __name__ == '__main__': app.run(debug=True) db.create_all() # 執行所有的類,進行建表。roles 和 user表創建成功。 r1 = Role(name="admin") # 給roles表中插入數據 db.session.add(r1) db.session.commit()
刪除所有的表
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 將這個從False改為True,請求后數據庫自動提交數據變動,要不然刪除不成功
if __name__ == '__main__':
app.run(debug=True)
db.drop_all() # 刪除所有的表
db.session.commit()
再次創建所有表
if __name__ == '__main__': app.run(debug=True) db.create_all() db.session.commit()
再次執行刪除所有的表
if __name__ == '__main__': app.run(debug=True) db.drop_all() db.session.commit() 但是結果:表依然沒有刪除掉
到底是什么原因呢?
解決辦法:重新啟動flask框架,后再次執行后,才能實現刪除表。
注意:重新建表和插入數據,也得重啟flask框架才能生效。
if __name__ == '__main__': app.run(debug=True) db.create_all() r1 = Role("admin") r2 = Role("no_admin") db.session.add_all([r1, r2]) db.session.commit()
問題:只執行了創表語句,插入語句沒有執行,什么原因?是不是因為要db.create_all()也要用db.session.commit()
if __name__ == '__main__': app.run(debug=True) db.create_all() db.session.commit() r1 = Role(name="admin") r2 = Role(name="noadmin") db.session.add_all(r1,r2) db.session.commit()
更改后:依然只能執行建表語句,插入數據不成功,到底是什么原因呢?原因是列表 db.session.add_all([r1,r2])沒有加列表。然后還是要重啟,框架插入語句才能被查詢到。
全部的問題:框架運行到app.run()就阻塞了,當關閉框架時,會執行到,后面的語句,語句才生效,我太笨了。
繼續連續兩次ctrl+s框架自動刷新,報錯:
sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1062, "Duplicate entry 'aaaaaa' for key 'name'") [SQL: 'INSERT INTO title (name) VALUES (%(name)s)'] [parameters: {'name': 'aaaaaa'}]
原因是:username設置的 unique=True,再次插入遇到重復的名字就報錯了。
三:sqlalchemy語句的操作
實例:通過python shell 的方式操作數據庫
終端中打開 ipython
輸入 from mysql_tesst impoty User,Role 報錯:
Non-ASCII character '\xe7' in file mysql_test.py on line 16, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details。
原因是:ipython 版本默認使用的是 Python2.7.12 在python2的版本中,程序中有中文或者中文注釋,第一行必須加上,# encoding: utf-8。
pip3 install ipython 將ipython的版本換成python3的版本就行了
下面將使用python shell的ipython3操作數據庫
1.表中插入數據
from mysql_test import User,db r1 = Role(name="Admin2") # 1.模型定義: print(r1.id) # None db.session.add(r1) # 2.增加模型到數據庫的操作層 db.session.commit() # 3.將模型轉換為mysql的原生語句,進行插入數據。 print(r1.id) # 3 # 獲取表中某個字段,直接通過實例屬性r1.id進行取值,方便。 select id from roles where name="Admin2"
# 為什么id不是按照順序排列的,
# 原因是:id字段設置時候,只是設置了為primary key並沒有設置為自增類型,auto_increment
2. 修改表中的字段信息
還是在上次的shell基礎上進行操作 要求:將表中的Admin2字典修改為admin2 r1.name = "admin2" # 通過賦值的方式修改表中name的值 db.session.add(r1) db.session.commit() print(r1.name) # admin2
3. 刪除表的數據
# 接着上面的shell db.session.delete(r1) db.session.commit()
4.查詢數據:sqlalchemy提供了 query對象進行數據查詢
Role.query.all() # query.all()表示查詢所有的數據 [<Role admin>, <Role noadmin>] 查詢操作,沒有修改表的結構,因此不需要session.commit():返回的是查詢的對象
返回的樣式為什么是這樣呢?
def __repr__(self):
return "<Role %s>" % self.username
原因是:模型類中定義的這個函數進行決定的。
查詢數據query配合過濾器filter可以更加准確的查詢所需要的數據
User.query.filter_by(username="張惠妹").all() [<User 張惠妹>] # 顯示的樣式同上

查詢users中用戶id大於2的所有用戶
User.query.filter_by(id>1).all() # 原因:filter_by只能用於等值過濾。 User.query.filter(id>1).all() # 原因:id 應該改為User.id 表示是這個表的id字段。 # 以上兩種方式的查詢均報錯: unorderable types: builtin_function_or_method() > int()
擴展:filter()中條件的寫法
users = User.query.filter(條件1).first()
條件的寫法:
User.name.endswith('g')
User.name.startswith('g')
User.name.containswith('g')
User.name == “laowang”
User.age == 12
User.age > 12
User.id.in_(列表)
查詢users中的id大於2且名字為張學良的用戶
User.query.filter(User.id>1 ,User.username=="張學良").all() [<User 張學良>]
擴展:filter()中多條件查詢的寫法
users = User.query.filter(條件1,條件2,條件3).first()
users = User.query.filter(or_(條件1,條件2,條件3)).first()
users = User.query.filter(not_(條件1)).all()
其他的過濾條件
排序 User.query.order_by(字段.哪一種排序).all() User.query.order_by(User.name.desc()).all() 分頁 aa = User.query.paginate(第幾頁,每一頁幾條) aa.pages aa.page aa.items
執行函數
3.視圖中操作數據庫
# todo