ORM
ORM 全拼Object-Relation Mapping
,中文意為 對象-關系映射。主要實現模型對象到關系數據庫數據的映射
優點 :
-
只需要面向對象編程, 不需要面向數據庫編寫代碼.
-
對數據庫的操作都轉化成對類屬性和方法的操作.
-
不用編寫各種數據庫的
sql語句
.
-
-
實現了數據模型與數據庫的解耦, 屏蔽了不同數據庫操作上的差異.
-
不再需要關注當前項目使用的是哪種數據庫。
-
通過簡單的配置就可以輕松更換數據庫, 而不需要修改代碼.
-
缺點 :
-
相比較直接使用SQL語句操作數據庫,有性能損失.
-
根據對象的操作轉換成SQL語句,根據查詢的結果轉化成對象, 在映射過程中有性能損失.
flask默認提供模型操作,但是並沒有提供ORM,所以一般開發的時候我們會采用flask-SQLAlchemy模塊來實現ORM操作。
SQLAlchemy是一個關系型數據庫框架,它提供了高層的 ORM 和底層的原生數據庫的操作。flask-sqlalchemy 是一個簡化了 SQLAlchemy 操作的flask擴展。
SQLAlchemy: https://www.sqlalchemy.org/
中文文檔: https://www.osgeo.cn/sqlalchemy/index.html
安裝 flask-sqlalchemy【清華源】
pip3 install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
安裝flask-mysqldb時,注意
安裝 flask-mysqldb的時候,python底層依賴於一個底層的模塊 mysql-client模塊
如果沒有這個模塊,則會報錯如下:
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-21hysnd4/mysqlclient/
解決方案:sudo apt-get install libmysqlclient-dev python3-dev
運行上面的安裝命令如果再次報錯如下:
dpkg 被中斷,您必須手工運行 ‘sudo dpkg --configure -a’ 解決此問題。
則根據提示執行命令以下命令,再次安裝mysqlclient
sudo dpkg --configure -a
apt-get install libmysqlclient-dev python3-dev
解決了mysqlclient問題以后,重新安裝 flask-mysqldb即可。
1pip3 install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
class Config(object): DEBUG = True SECRET_KEY = "*(%#4sxcz(^(#$#8423" # 數據庫鏈接配置 = 數據庫名稱://登錄賬號:登錄密碼@數據庫主機IP:數據庫訪問端口/數據庫名稱?charset=編碼類型 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 動態追蹤修改設置,如未設置只會提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True #查詢時會顯示原始SQL語句 SQLALCHEMY_ECHO = True 配置完成需要去 MySQL 中創建項目所使用的數據庫 $ mysql -uroot -p123 mysql > create database students charset=utf8mb4;
-
-
會話用 db.session 表示。在准備把數據寫入數據庫前,要先將數據添加到會話中然后調用 db.commit() 方法提交會話。
-
-
在 Flask-SQLAlchemy 中,查詢操作是通過 query 對象操作數據。
-

from flask import Flask,render_template,request from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(): DEBUG = True # 數據庫鏈接配置 # SQLALCHEMY_DATABASE_URI = "mysql://賬號:密碼@IP/數據庫名?編碼" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 動態追蹤修改設置,如未設置只會提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查詢時會顯示原始SQL語句 SQLALCHEMY_ECHO = True app.config.from_object(Config) db = SQLAlchemy() db.init_app(app) """創建模型類""" class Student(db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True,comment="主鍵ID") name = db.Column(db.String(250), comment="姓名") age = db.Column(db.Integer, comment="年齡") sex = db.Column(db.Boolean, default=False, comment="性別") money = db.Column(db.DECIMAL(8,2), nullable=True, comment="錢包") def __repr__(self): return self.name class Teacher(db.Model): __tablename__ = "tb_teacher" id = db.Column(db.Integer, primary_key=True, comment="主鍵ID") name = db.Column(db.String(250), comment="姓名") sex = db.Column(db.Boolean, default=False, comment="性別") option = db.Column(db.Enum("講師","助教","班主任"), default="講師", comment="教職") def __repr__(self): return self.name class Course(db.Model): __tablename__ = "tb_course" id = db.Column(db.Integer, primary_key=True, comment="主鍵ID") name = db.Column(db.String(250), unique=True, comment="課程名稱") price = db.Column(db.Numeric(6, 2)) def __repr__(self): return self.name @app.route("/") def index(): return "Ok" if __name__ == '__main__': # with app.app_context(): # db.create_all() # 根據模型創建所有的數據表 # # db.drop_all() # 刪除模型對應的所有數據表 app.run()

from flask import Flask,render_template,request from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(): DEBUG = True # 數據庫鏈接配置 # SQLALCHEMY_DATABASE_URI = "mysql://賬號:密碼@IP/數據庫名?編碼" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 動態追蹤修改設置,如未設置只會提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查詢時會顯示原始SQL語句 SQLALCHEMY_ECHO = True app.config.from_object(Config) db = SQLAlchemy() db.init_app(app) """創建模型類""" class Student(db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True,comment="主鍵ID") name = db.Column(db.String(250), comment="姓名") age = db.Column(db.Integer, comment="年齡") sex = db.Column(db.Boolean, default=False, comment="性別") money = db.Column(db.DECIMAL(8,2), nullable=True, comment="錢包") def __repr__(self): return self.name class Teacher(db.Model): __tablename__ = "tb_teacher" id = db.Column(db.Integer, primary_key=True, comment="主鍵ID") name = db.Column(db.String(250), comment="姓名") sex = db.Column(db.Boolean, default=False, comment="性別") option = db.Column(db.Enum("講師","助教","班主任"), default="講師", comment="教職") def __repr__(self): return self.name class Course(db.Model): __tablename__ = "tb_course" id = db.Column(db.Integer, primary_key=True, comment="主鍵ID") name = db.Column(db.String(250), unique=True, comment="課程名稱") price = db.Column(db.Numeric(6, 2)) def __repr__(self): return self.name @app.route("/") def index(): """數據庫基本操作""" """添加數據""" # 添加一條數據 # student1 = Student(name="xiaohong",age=16,money=100,sex=True) # db.session.add(student1) # db.session.commit() # 批量添加多條數據 # data_list = [ # Student(name="xiaohui1號",age=16,money=1000, sex=True), # Student(name="xiaohui2號",age=16,money=1000, sex=True), # Student(name="xiaohui3號",age=16,money=1000, sex=True), # Student(name="xiaohui4號",age=16,money=1000, sex=True), # Student(name="xiaohui5號",age=16,money=1000, sex=True), # Student(name="xiaohui6號",age=16,money=1000, sex=True), # ] # db.session.add_all(data_list) # db.session.commit() """查詢數據""" # 根據主鍵ID查詢一條數據,如果ID不存在,則返回None不會報錯! # student = Student.query.get(100) # if student is None: # print("當前學生不存在!") # else: # print(student) # print(student.name,student.age) # 獲取屬性 # 根據查詢條件獲取一條數據 # 模型.query.filter(模型.字段==條件值).first() # student = Student.query.filter(Student.id==1).first() # print(student) # print(student.name,student.money) # 根據查詢條件獲取多條數據 # 模型.query.filter(模型.字段==條件值).all() # student_list = Student.query.filter(Student.id < 5).all() # print(student_list) # """打印效果; # [xiaoming, xiaohong, xiaohui1號, xiaohui2號] # """ # for student in student_list: # print(student.name, student.money) """更新數據""" # 先查詢后修改 # student = Student.query.filter(Student.name=="xiaoming").first() # student.money+=1000 # db.session.commit() # 直接根據條件修改 # Student.query.filter(Student.name=="xiaoming",Student.money==1100).update({Student.money:2000}) # 樂觀鎖 # 實現類似django的F函數效果,字段值累加 # Student.query.filter(Student.name=="xiaoming").update({Student.money:Student.money+500}) # 樂觀鎖 # db.session.commit() """刪除數據""" # 先查詢后刪除 # student = Student.query.filter(Student.name=="xiaohui6號").first() # db.session.delete(student) # db.session.commit() # 直接根據條件進行刪除操作 Student.query.filter(Student.name=="xiaohui5號").delete() db.session.commit() return "Ok" if __name__ == '__main__': # with app.app_context(): # db.create_all() # 根據模型創建所有的數據表 # # db.drop_all() # 刪除模型對應的所有數據表 app.run()
分組查詢和分組查詢結果過濾

from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(): # DEBUG調試模式 DEBUG = True # json多字節轉unicode編碼 JSON_AS_ASCII = False # 數據庫鏈接配置 # SQLALCHEMY_DATABASE_URI = "mysql://賬號:密碼@IP/數據庫名?編碼" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 動態追蹤修改設置,如未設置只會提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查詢時會顯示原始SQL語句 SQLALCHEMY_ECHO = True app.config.from_object(Config) db = SQLAlchemy() db.init_app(app) """創建模型類""" class Student(db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True,comment="主鍵ID") name = db.Column(db.String(250), comment="姓名") age = db.Column(db.Integer, comment="年齡") sex = db.Column(db.Boolean, default=False, comment="性別") money = db.Column(db.DECIMAL(8,2), nullable=True, comment="錢包") def __repr__(self): return self.name class Teacher(db.Model): __tablename__ = "tb_teacher" id = db.Column(db.Integer, primary_key=True, comment="主鍵ID") name = db.Column(db.String(250), comment="姓名") sex = db.Column(db.Boolean, default=False, comment="性別") option = db.Column(db.Enum("講師","助教","班主任"), default="講師", comment="教職") def __repr__(self): return self.name class Course(db.Model): __tablename__ = "tb_course" id = db.Column(db.Integer, primary_key=True, comment="主鍵ID") name = db.Column(db.String(250), unique=True, comment="課程名稱") price = db.Column(db.Numeric(6, 2)) def __repr__(self): return self.name @app.route("/") def index(): from sqlalchemy import func """ group_by 分組查詢""" # 查詢男生和女生的最大年齡 Student.query.group()以下Student不支持聚合查詢 # ret = db.session.query(Student.sex,func.max(Student.age)).group_by(Student.sex).all() # print(ret) # 查詢出男生和女生年齡大於18的人數 # having是針對分組的結果進行過濾處理,所以having能調用的字段,必須是分組查詢結果中的字段,否則報錯!! # ret = db.session.query(Student.sex,Student.age,func.count(Student.age)).group_by(Student.sex,Student.age).having(Student.age>18).all() # print(ret) """執行原生SQL語句,返回結果不是模型對象, 是列表和元祖""" # 查詢多條 # ret = db.session.execute("select id,name,age,IF(sex,'男','女') from tb_student").fetchall() # print(ret) # # 查詢單條 # ret = db.session.execute("select * from tb_student where id = 3").fetchone() # print(ret) # 添加/修改/刪除 # db.session.execute("UPDATE tb_student SET money=(money + %s) WHERE age = %s" % (200, 22)) # db.session.commit() # 查詢出女生和男生中大於18歲的人數 ret = db.session.execute("SELECT IF(sex,'男','女'), count(id) from (SELECT id,name,age,sex FROM `tb_student` WHERE age>18) as stu group by sex").fetchall() print(ret) return "Ok" if __name__ == '__main__': app.run()