1.CRCD操作
CRUD(create、read、upgrade、delete)是数据库的基本操作。
Create:添加数据等
用ORM创建一条数据很简单,使用ORM模型创建一个对象,然后添加到会话中,再进行commit操作即可。
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column from sqlalchemy import MetaData,Integer,String from flask_migrate import Migrate app = Flask(__name__) app.config.from_object(config) # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) migrate = Migrate(app=app,db=db) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) @app.route('/create') def create(): # user = User(username="张三",password="1122") # db.session.add(user) user1=User(username="李四",password="2233") user2=User(username="王五",password="3344" db.session.add_all([user1,user2]) db.session.commit() return "数据添加成功!" if __name__ == '__main__': app.run()
Read:查询数据
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column from sqlalchemy import MetaData,Integer,String from flask_migrate import Migrate app = Flask(__name__) app.config.from_object(config) # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) migrate = Migrate(app=app,db=db) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) @app.route('/read') def read(): # 1.获取User中所有数据,查找多条数据使用db.sesstion.scalars # users=db.session.execute(db.select(User)).scalars().all() # 或 # users=db.session.scalars(db.select(User)).all() # print(users) # 2.获取主键为1的User对象,查找一条数据,使用db.sesstion.scalar # 里使用一个快捷方式,就是直接调用scalar,不用先调用execute再调用scalar # user=db.session.execute(db.select(User).where(User.id==1)).scalar() # 或 # user=db.session.scalar(db.select(User).where(User.id==1)) # print(user) # 3.根据username排序,默认是升序,如果想要降序,User.username.desc() users=db.session.scalars(db.select(User).order_by(User.username.desc())).all() print(users) return "数据查找成功!" if __name__ == '__main__': app.run()
Update:修改数据
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column from sqlalchemy import MetaData,Integer,String from flask_migrate import Migrate app = Flask(__name__) app.config.from_object(config) # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) migrate = Migrate(app=app,db=db) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) @app.route('/update') def update(): # 1.查找出来再修改 # user=db.session.scalar(db.select(User).where(User.username=="张三")) # user.username="张张" # # 同步到数据库中 # db.session.commit() # 2.直接修改 db.session.execute(db.update(User).where(User.password=="1122").values(password="1111")) db.session.commit() return "数据修改成功!" if __name__ == '__main__': app.run()
Delete:删除数据
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column from sqlalchemy import MetaData,Integer,String from flask_migrate import Migrate app = Flask(__name__) app.config.from_object(config) # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) migrate = Migrate(app=app,db=db) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) @app.route('/delete') def delete(): # 1.查找出来再删除 # user=db.session.scalar(db.select(User).where(User.username=="王五")) # db.session.delete(user) # db.session.commit() # return "数据删除成功!" # 2.直接删除 db.session.execute(db.delete(User).where(User.username=="李四")) db.session.commit() if __name__ == '__main__': app.run()
2.表关系
关系型数据库可以让多个表建立关系,这种表关系可以存储复杂的数据,也可以使查询迅速。在Flask-SQLAlchemy中,同样也支持表关系的建立,表关系建立的前提是通过数据库层面的外键实现。表关系总体分为三种:一对一、一对多(多对一)、多对多。
外键
外键是数据库层面的技术,SQLAlchemy中,可以通过ForeignerKey来实现外键。
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column from sqlalchemy import MetaData,Integer,String,ForeignKey from flask_migrate import Migrate app = Flask(__name__) app.config.from_object(config) # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) migrate = Migrate(app=app,db=db) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) department_id:Mapped[int]=mapped_column(Integer,ForeignKey('department.id'), nullable=True) class Department(db.Model): __tablename__ = 'department' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) name:Mapped[str]=mapped_column(String(50),nullable=False) @app.route('/') def hello_world(): # put application's code here return 'Hello World!' if __name__ == '__main__': app.run()y
一对多(多对一)
通过外键,可以创建一对多或多对一的关系映射,以上代码规定了一个用户只能属于一个部门,那么Department和User就是一对多的关系,Department是一,User是多。
表通过 department_id外键关联department表。
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column,relationship from sqlalchemy import MetaData,Integer,String,ForeignKey from flask_migrate import Migrate from typing import List app = Flask(__name__) app.config.from_object(config) # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) migrate = Migrate(app=app,db=db) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) department_id:Mapped[int]=mapped_column(Integer,ForeignKey('department.id'), nullable=True) department:Mapped["Department"]=relationship("Department", back_populates="users") class Department(db.Model): __tablename__ = 'department' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) name:Mapped[str]=mapped_column(String(50),nullable=False) users:Mapped[List[User]]=relationship("User",back_populates="department")
上述代码,针对department_id创建一个属性department。另外,在relationship中还定义了一个属性back_populates,是用来标记对方在访问本类的对象时,用的什么属性。一对多使用示例代码如下:
def one2may(): # 1.通过user添加department # department = Department(name="技术部") # # user=User(username="张三",password="1111",department=department) # user=User(username="张三",password="1111") # user.department=department # db.session.add(user) # db.session.commit() # 2.通过department添加user # department =db.session.scalar(db.select(Department).where(Department.id==1)) # user=User(username="李四",password="2222") # department.users.append(user) # db.session.commit() # 3.通过user访问department # user=db.session.scalar(db.select(User).where(User.id==1)) # department=user.department # print(f"部门名称为:{department.name}") # 4.通过department获取所有当前部门下的用户 department=db.session.scalar(db.select(Department).where(Department.id==1)) users=department.users for user in users: print(user.id,user.username,user.password) return "一对多数据操作成功!"
一对一
存储一些不常用的数据时,可以创建一个UserExtension表,那么User和UserExtension之间就是一对一的关系,也就是一个User只有一个UserExtension,一个UserExtension只能被一个User使用。User和UserExtension之间一对一的关系模型如下:
class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) email:Mapped[str]=mapped_column(String(200),nullable=True) department_id:Mapped[int]=mapped_column(Integer,ForeignKey('department.id'), nullable=True) department:Mapped["Department"]=relationship("Department", back_populates="users") user_extension:Mapped["UserExtension"]=relationship("UserExtension", back_populates="user",uselist=False) class UserExtension(db.Model): __tablename__ = 'user_extension' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) university:Mapped[str]=mapped_column(String(50),nullable=False) user_id:Mapped[int]=mapped_column(Integer,ForeignKey('user.id'),unique= True) user:Mapped[User]=relationship("User",back_populates="user_extension")
上述代码中,参数uselist=False约束了user_extension时一个对象,而不是一个列表。在UserExtension模型中,设计了user_id字段的unique=True,也就是user_id在UserExtension中是唯一的,也保证了一对一的关系。一对一使用相关代码如下:
def one2one(): user:User=db.session.scalar(db.select(User).where(User.id==1)) user.user_extension=UserExtension(university="北京大学") db.session.commit() return "一对一操作完成!"
多对多
多对多通常需要经过中间表来实现。假设有一个权限表,和部门之间的关系是多对多,也就是一个部门有多个权限,一个权限可以针对多个部门。多对多示例代码如下:
department_permission_table = Table( "department_permission", db.metadata, Column("department_id", Integer, ForeignKey("department.id"), primary_key=True), Column("permission_id", Integer, ForeignKey("permission.id"), primary_key=True), ) class Department(db.Model): __tablename__ = 'department' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) name:Mapped[str]=mapped_column(String(50),nullable=False) users:Mapped[List[User]]=relationship("User",back_populates="department") permissions:Mapped[List["Permission"]]=relationship( "Permission", secondary=department_permission_table, back_populates="departments" ) class Permission(db.Model): __tablename__ = 'permission' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) name:Mapped[str]=mapped_column(String(50),nullable=False) departments:Mapped[List[Department]]=relationship( "Department", secondary=department_permission_table, back_populates="permissions" )
上述代码中,使用department_permission_table中间表来存储两者之间的关系,并创建了department_id作为department.id的外键,创建了permission_id作为permission.id的外键,并使用它们作为主键。然后在Department和Permission表中分别添加两个属性Department.permissions和Permission.departments,这两个属性是relationship创建的,并且指定了secondary参数为中间表department_permission_table,这样SQLAlchemy就会自动绑定两者之间的关系。多对多使用代码如下:
def many2many(): # 1.通过department添加permission # department=db.session.scalar(db.select(Department).where(Department.id==1)) # permissions=[ # Permission(name="访问首页"), # Permission(name="访问用户") # ] # # 可以将department.permissions当作一个列表 # # department.permissions.append(permissions[0]) # # department.permissions.append(permissions[1]) # # 或用以下代码 # department.permissions.extend(permissions) # db.session.commit() # 2.移除多对多关系的数据 department=db.session.scalar(db.select(Department).where(Department.id==1)) permission=db.session.scalar(db.select(Permission).where(Permission.name=="访问首页")) department.permissions.remove(permission) db.session.commit() return "多对多操作完成!"