Flask框架beginning4

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 "多对多操作完成!"
相关推荐
cm65432013 小时前
用Python破解简单的替换密码
jvm·数据库·python
wan9yu13 小时前
为什么你需要给 LLM 的数据"加密"而不是"脱敏"?我写了一个开源工具
python
摇滚侠14 小时前
你是一名 java 程序员,总结定义数组的方式
java·开发语言·python
这个名有人用不14 小时前
解决 uv 虚拟环境使用 pip 命令提示command not found的办法
python·pip·uv·claude code
Oueii14 小时前
掌握Python魔法方法(Magic Methods)
jvm·数据库·python
2501_9083298515 小时前
使用Python自动收发邮件
jvm·数据库·python
2501_9083298515 小时前
NumPy入门:高性能科学计算的基础
jvm·数据库·python
2401_8747325316 小时前
Python Web爬虫入门:使用Requests和BeautifulSoup
jvm·数据库·python
平常心cyk16 小时前
Python基础快速复习——集合和字典
开发语言·数据结构·python