Flask数据库操作_SQLALchemy学习

系列文章目录


前言

1.SQLAlchemy 是 Python 中一个通过 ORM 操作数据库的框架。

2.SQLAlchemy对象关系映射器提供了一种方法,用于将用户定义的Python类与数据库表相关联,并将这3.3些类(对象)的实例与其对应表中的行相关联。

3.它包括一个透明地同步对象及其相关行之间状态的所有变化的系统,称为工作单元,以及根据用户定义的类及其定义的彼此之间的关系表达数据库查询的系统。

4.可以让我们使用类和对象的方式操作数据库,从而从繁琐的 sql 语句中解脱出来。

5.ORM 就是 Object Relational Mapper 的简写,就是关系对象映射器的意思。


一、创建ORM映射

1、主动创建映射

导入 from sqlalchemy.ext.declarative import declarative_base
每一个映射类都需要继承这个基类

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#第二步:定义Python类和表的映射
class Person(Base):  #必须继承基类
    __tablename__='t_person'  # t_person 是在数据库呈现的表名。
    id=Column(name='id',type_=Integer,primary_key=True,autoincrement=True)
    name=Column(name='name',type_=String(255))
    age=Column(name='age',type_=Integer)
    address=Column(String(255))
    country=Column(String(50)) #创建表之后新加  只能执行先执行删除后在执行创建表,才能将新添的列名创建进去。

#第三步:创建表  (先删除表后创建)
Base.metadata.drop_all() #删除表
Base.metadata.create_all() #创建表

SQLAlchemy常用数据类型

  1. Integer:整形,映射到数据库中是int类型。
  2. Float:浮点类型,映射到数据库中是float类型。他占据的32位。
  3. Double:双精度浮点类型,映射到数据库中是double类型,占据64位 (SQLALCHEMY中没有)。
  4. String:可变字符类型,映射到数据库中是varchar类型.
  5. Boolean:布尔类型,映射到数据库中的是tinyint类型。
  6. DECIMAL:定点类型。是专门为了解决浮点类型精度丢失的问题的。在存储钱相关的字段的时候建议大家都
    使用这个数据类型。并且这个类型使用的时候需要传递两个参数,第一个参数是用来标记这个字段总能能存
    储多少个数字,第二个参数表示小数点后有多少位。
  7. Enum:枚举类型。指定某个字段只能是枚举中指定的几个值,不能为其他值。在ORM模型中,使用Enum来
    作为枚举。
  8. Date:存储时间,只能存储年月日。映射到数据库中是date类型。在Python代码中,可以使用
    datetime.date 来指定。
  9. DateTime:存储时间,可以存储年月日时分秒毫秒等。映射到数据库中也是datetime类型。在Python代码
    中,可以使用 datetime.datetime 来指定。
  10. Time:存储时间,可以存储时分秒。映射到数据库中也是time类型。在Python代码中,可以使用
    datetime.time 来创建值。
  11. Text:存储长字符串。一般可以存储6W多个字符。如果超出了这个范围,可以使用LONGTEXT类型。映射到
    数据库中就是text类型。
  12. LONGTEXT:长文本类型,映射到数据库中是longtext类型。
    注意:这个类型属于Mysql方言里面的

column常用参数

  1. primary_key:True设置某个字段为主键。
  2. autoincrement:True设置这个字段为自动增长的。
  3. default:设置某个字段的默认值。在发表时间这些字段上面经常用。
  4. nullable:指定某个字段是否为空。默认值是True,就是可以为空。
  5. unique:指定某个字段的值是否唯一。默认是False。
  6. onupdate:在数据更新的时候会调用这个参数指定的值或者函数。在第一次插入这条数据的时候,不会用
    onupdate的值,只会使用default的值。常用于是 update_time 字段(每次更新数据的时候都要更新该字段
    值)。
  7. name:指定ORM模型中某个属性映射到表中的字段名。如果不指定,那么会使用这个属性的名字来作为字
    段名。如果指定了,就会使用指定的这个值作为表字段名。这个参数也可以当作位置参数,在第1个参数来指

2、自动从数据库中映射

  • 自动从数据库中映射就是,把数据里面的表给映射出来。
from sqlalchemy import *
from datetime import datetime
from sqlalchemy.ext.automap import automap_base

# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#自动映射
Base=automap_base()
Base.prepare(engine,reflect=True)

#获取所有表的映射类(该数据下所有表)
tables=Base.classes.keys()
print(tables)
print('=======================')

#可以重定义类的名(定义出要映射出来的表)
Person=Base.classes.t_person

#得到当前类中所有的属性
keys=Person.__table__.columns.keys()
print(keys)

3、数据的crud操作

  1. 构建session对象:
  2. 所有和数据库的ORM操作都必须通过session的会话对象来实现。
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#第二步:定义Python类和表的映射
class Person(Base):
    __tablename__='t_person'
    id=Column(name='id',type_=Integer,primary_key=True,autoincrement=True)
    name=Column(name='name',type_=String(255))
    age=Column(name='age',type_=Integer)
    address=Column(String(255))
    country=Column(String(50)) #创建表之后新加

    def __str__(self):
        return "Person[id:{},name:{},age:{}]".format(self.id,self.name,self.age)

#添加操作

session=sessionmaker(engine)() #注意:sessionmaker 返回一个函数
def add():
    #创建session
    #
    p1=Person(name='张三',age=18,address='海定区',country='中国')
    p2=Person(name='李四',age=38,address='海定区',country='中国')
    p3=Person(name='王五',age=48,address='海定区',country='中国')
    #session.add(p1)
    #添加操作
    session.add_all([p2,p3])
    session.commit()

#查找操作
def select():
    p=session.query(Person).first() #查询一个
    p2=session.query(Person).all() #查询所有
    #print(p2[0])
    for p in p2:
        pass
        #print(p)

    #查询年龄大于18岁的
    list=session.query(Person).filter(Person.age > 18)

    #查询大于18并且小于48的
    list2=session.query(Person).filter(Person.age > 18,Person.age<48)
    for p in list2:
        #print(p)
        pass

    #查询年龄大于18的总人数
    resulit=session.query(func.count(Person.id)).filter(Person.age> 18).first()
    #print(resulit[0]) #result是一个元组


#修改
def update():
    p=session.query(Person).filter(Person.id==1).first()
    print(p.age)
    p.age=60
    session.commit()

#删除
def delete():
    p = session.query(Person).filter(Person.id == 1).first()
    print(p)
    session.delete(p)
    session.commit()

if __name__ == '__main__':
    delete()

二、ORM的关联关系

1. 表的外键关联

1、使用SQLAlchemy创建外键非常简单。在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。
2、从表中外键的字段,必须和主表的主键字段类型保持一致。

  • 外键的删除选项
    1.RESTRICT:若子表中有父表对应的关键数据,删除父表对应数据,会阻止删除。默认项
    2,NO ACTION: 在MYSQL中,同RESTRICT.
    3.CASCADE: 级联删除
    4.SET NULL: 父表对应数据库被删除时,子表对应数据项会被设置为NULL

注意:在多方设置了外键约束,只能在一方先填加数据后,再在多方填加数据。

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import sessionmaker
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#部门和员工之间,是一种典型的一(主)对多(从)
class Detp(Base):
    __tablename__='t_dept'
    deptno=Column(Integer,primary_key=True) #部门编号
    dname=Column(String(255)) #部门名字
    city=Column(String(50)) #城市

#员工表
class Emp(Base):
    __tablename__='t_emp'
    emp_no=Column(Integer,primary_key=True)
    ename=Column(String(50))
    job=Column(String(50))
    hire_date=Column(String(50))
    sal=Column(String(50))
    '''
    外键的删除选项
    1.RESTRICT:若子表中有父表对应的关键数据,删除父表对应数据,会阻止删除。默认项
    2,NO ACTION: 在MYSQL中,同RESTRICT.
    3.CASCADE: 级联删除
    4.SET NULL: 父表对应数据库被删除时,子表对应数据项会被设置为NULL
    '''
    dept_no=Column(Integer,ForeignKey('t_dept.deptno',ondelete='CASCADE'))#外键

#Base.metadata.create_all()

d1=Detp(dname='行政楼',city='北京')
e1=Emp(ename='张三',job='python开发',hire_date=date(2020,11,22),sal=5555.1,dept_no=1)

session=sessionmaker(engine)()
#因为设置了外键约束,所以只能先添加部门表在添加员工表
# #session.add(d1)
# session.add(e1)
#session.commit()
#删除
dept=session.query(Detp).first()
session.delete(dept)
session.commit()

2.ORM的relationship属性

  • SQLAlchemy提供了一个 relationship ,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属
    性访问的方式就可以访问得到了。另外,可以通过 backref 来指定反向访问的属性名称。newss是指有多篇新
    闻。他们之间的关系是一个“一对多”的关系。

1.ORM中的一对多/多对一

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import sessionmaker,relationship
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#部门和员工之间,是一种典型的一(主)对多(从)
class Detp(Base):
    __tablename__='t_dept'
    deptno=Column(Integer,primary_key=True) #部门编号
    dname=Column(String(255)) #部门名字
    city=Column(String(50)) #城市
    #代表当前部门下的所有员工列表,这种 写法不是最好的,最优的写法只要其中一个对象中关联就可以
    #emps=relationship("Emp") #参数必须是另外一个相关联的类名

    def __str__(self):
        return "DEPT:<部门编号:{},部门名字:{}>".format(self.deptno,self.dname)
#员工表
class Emp(Base):
    __tablename__='t_emp'
    emp_no=Column(Integer,primary_key=True)
    ename=Column(String(50))
    job=Column(String(50))
    hire_date=Column(String(50))
    sal=Column(String(50))
    '''
    外键的删除选项
    1.RESTRICT:若子表中有父表对应的关键数据,删除父表对应数据,会阻止删除。默认项
    2,NO ACTION: 在MYSQL中,同RESTRICT.
    3.CASCADE: 级联删除
    4.SET NULL: 父表对应数据库被删除时,子表对应数据项会被设置为NULL
    '''
    dept_no=Column(Integer,ForeignKey('t_dept.deptno',ondelete='RESTRICT'))#外键

    dept=relationship('Detp',backref='emps') #backref='emps' 反向关联

    def __str__(self):
        return "EMP:<员工编号;{},员工姓名:{}>".format(self.emp_no,self.ename)

#先删除在创建
# Base.metadata.drop_all()
# Base.metadata.create_all()

d1=Detp(dname='行政楼',city='北京')
e1=Emp(ename='张三',job='python开发',hire_date=date(2020,11,22),sal=5555.1,dept_no=1)
e2=Emp(ename='李四',job='python开发',hire_date=date(2020,11,22),sal=5555.1,dept_no=1)
#
session=sessionmaker(engine)()
#因为设置了外键约束,所以只能先添加部门表在添加员工表
#session.add(d1)
# session.add(e2)
# session.commit()


#删除
# dept=session.query(Detp).first()
# session.delete(dept)
#session.commit()

#查询  部门表
d=session.query(Detp).first()
#print(d)
for e in d.emps:
    #print(e)
    pass

#员工表
e=session.query(Emp).filter(Emp.emp_no==2).first()
print(e)
print(e.dept)

2.ORM中的一对一

  • 一对一对应的关系的话,在其中那个类(表)设立外键都可以的,注意的是在那个设立外键就要在那个表设relationship参数。
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import *
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#preson和身份证号是一对一的关系
#第一种写法:把uselist=false 加在没有外键的对象中(主表)
#第二种写法:在主表中不需要维护关联关系
class Person(Base):
    __tablename__='t_person'
    id=Column(name='id',type_=Integer,primary_key=True,autoincrement=True)
    name=Column(name='name',type_=String(255))
    age=Column(name='age',type_=Integer)
    address=Column(String(255))
    country=Column(String(50)) #创建表之后新加

    #当前人对应的身份证号
    #是一个对象,不是列表
    #第一种写法,第二种写法把它注释掉
    #d_card=relationship('Id_Card',uselist=False)

    def __str__(self):
        return "Person:<人的编号:{},人的名字:{}>".format(self.id,self.name)
#身份证  定义外键
class Id_Card(Base):
    __tablename__='t_id_card'
    card_number=Column(String(18),primary_key=True)
    p_id=Column(Integer,ForeignKey('t_person.id')) #外键

    #当前身份证对应的人
    person=relationship('Person',backref=backref('id_card',uselist=False))
    '''
    外键的删除选项
    1.RESTRICT:若子表中有父表对应的关键数据,删除父表对应数据,会阻止删除。默认项
    2,NO ACTION: 在MYSQL中,同RESTRICT.
    3.CASCADE: 级联删除
    4.SET NULL: 父表对应数据库被删除时,子表对应数据项会被设置为NULL
    '''

    def __str__(self):
        return "身份证编号;{}>".format(self.card_number)

#建表
#Base.metadata.create_all()

#创建session
session=sessionmaker(engine)()
#添加
def insert():
    c1=Id_Card(card_number='100001',p_id=1)
    c2=Id_Card(card_number='100002',p_id=2)
    c3=Id_Card(card_number='100003',p_id=3)

    session.add_all([c1,c2,c3])
    session.commit()

#查询
def cx():
    p=session.query(Person).first()
    # print(p)
    # print(p.id_card)

    #身份证号码查询
    card=session.query(Id_Card).first()
    print(card)
    print(card.person)

#修改
def update():
    p=session.query(Id_Card).filter(Id_Card.card_number=='100001').first()
    #print(p)
    p.p_id=4
    session.commit()

if __name__ == '__main__':
    #insert()
    cx()
    update()

3、ORM中多对多

  1. 多对多的关系需要通过一张中间表来绑定他们之间的关系。
  2. 先把两个需要做多对多的模型定义出来
  3. 使用Table定义一个中间表,中间表一般就是包含两个模型的外键字段就可以了,并且让他们两个来作为一
    个“复合主键”。
  4. 在两个需要做多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使
    用relationship的时候,需要传入一个secondary=中间表对象名
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import sessionmaker,relationship
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#学生和课程就是多对多的关系
#第一步创建中间表
tepm_tab=Table(
    't_temp_tab',
    Base.metadata,
    #第三步:定义中间表的两个外键字段作为联合主键
    Column('s_id',Integer,ForeignKey('t_student.id'),primary_key=True), #primary_key=True 复合键
    Column('c_id',Integer,ForeignKey('t_course.id'),primary_key=True)
)

#第二步创建两个模型
class Student(Base):
    __tablename__='t_student'
    id=Column(Integer,primary_key=True,autoincrement=True)
    name=Column(String(50))
    age=Column(Integer)

    #第四步:定义关联关系
    course_list=relationship('Course',backref='student_list',secondary=tepm_tab)

    def __repr__(self):
        return 'Student:name=%s'%self.name

class Course(Base):
    __tablename__='t_course'
    id=Column(Integer,primary_key=True,autoincrement=True)
    c_name=Column(String(50))

    def __repr__(self):
        return 'Course:id=%s'%self.id

#创建session
session=sessionmaker(engine)()
#创建表
def cjb():
    Base.metadata.create_all()


#插入数据
#  s1.course_list.append(c1)
#   s1.course_list.append(c2)
#   s2.course_list.append(c1)
#   s2.course_list.append(c2)
# 插入学生信息的同时参入所选的课程
def insert():
    s1=Student(name='zs',age=22)
    s2=Student(name='ls',age=28)

    c1=Course(c_name='数学')
    c2=Course(c_name='英语')

    s1.course_list.append(c1)
    s1.course_list.append(c2)
    s2.course_list.append(c1)
    s2.course_list.append(c2)

    session.add(s1)
    session.add(s2)
    session.commit()

#查询
def query():
    #查询学生
    # s1=session.query(Student).first()
    # print(s1)
    # print(s1.course_list)

    #查询课程
    c1=session.query(Course).first()
    print(c1)
    print(c1.student_list)

#修改
def update():
    s1=session.query(Student).filter(Student.id==1).first()
    #print(s1)

if __name__ == '__main__':
    #cjb()
    #insert()
    query()
    # update()

三、SQLALchemy的高级

1、排序与分页查询

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import sessionmaker,relationship
import random
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#学生和课程就是多对多的关系
#第一步创建中间表
tepm_tab=Table(
    't_temp_tab',
    Base.metadata,
    #第三步:定义中间表的两个外键字段作为联合主键
    Column('s_id',Integer,ForeignKey('t_student.id'),primary_key=True), #primary_key=True 复合键
    Column('c_id',Integer,ForeignKey('t_course.id'),primary_key=True)
)

#第二步创建两个模型
class Student(Base):
    __tablename__='t_student'
    id=Column(Integer,primary_key=True,autoincrement=True)
    name=Column(String(50))
    age=Column(Integer)

    #第四步:定义关联关系
    course_list=relationship('Course',backref='student_list',secondary=tepm_tab)

    def __repr__(self):
        return 'Student:name={},age={}'.format(self.name,self.age)

class Course(Base):
    __tablename__='t_course'
    id=Column(Integer,primary_key=True,autoincrement=True)
    c_name=Column(String(50))

    def __repr__(self):
        return 'Course:id=%s'%self.id

#创建session
session=sessionmaker(engine)()
#创建表
def cjb():
    Base.metadata.create_all()


#插入数据
def insert():
    student=[]
    for x in range(10):
        s=Student(name='name-%s'%x,age=random.randint(18,100))
        student.append(s)
    session.add_all(student)
    session.commit()
#排序
def query():
    #第一种排序:直接在query查询的时候加入order_by函数
    list=session.query(Student).order_by(Student.age).all() #默认升序
    list=session.query(Student).order_by(Student.age.desc()).all() #降序
    # print(list)
    # print(len(list))

    #分页查询
    #limit(可以限制查询的时候只查询前几条数据)
    a=session.query(Student).limit(5).all() #limit(n) 最多取n条数据
    b=session.query(Student).offset(2).limit(5).all() #offest(n) 过滤掉前面n条数据
    c=session.query(Student).slice(2,8).all() #从n条后面开始取,到m条结束
    d=session.query(Student)[1:5]#前开后闭 总共4条数据
    print(a)
    print(len(a))
    print('=================')

    print(b)
    print(len(b))
    print('=============')

    print(c)
    print(len(c))
    print('=============')

    print(d)
    print(len(d))
    print(len('============='))


#修改
def update():
    s1=session.query(Student).filter(Student.id==1).first()
    s1.age=18
    session.commit()
    print(s1)

if __name__ == '__main__':
    #cjb()
    #insert()
    # query()
    update()

2、懒加载

  1. 在一对多,或者多对多关系的时候,如果想要获取多的一方这一部分的数据的时候,往往能通过一个属性就可以全部获取了。
  2. 如有一个作者,想要这个作者的所有文章,通过user.articles就可以获取所有的。
    但有时候我们不想获取所有的数据,如只想获取这个作者今天发表的文章,那么这时候我们可以给relationship方
    法添加属性lazy=‘dynamic’,以后通过user.articles获取到的就不是一个列表,而是一个AppenderQuery对象了。这样就可以对这个对象再进行一层过滤和排序等操作。
  3. 通过 lazy=‘dynamic’ ,获取出来的多的那一部分的数据,就是一个 AppenderQuery 对象了。这种对象既可以
  4. 添加新数据,也可以跟 Query 一样,可以再进行一层过滤。
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from datetime import date
from sqlalchemy.orm import *
# 数据库的配置变量
HOSTNAME='127.0.0.1'
PORT='3306'
DATABASE='test'
USERNAME='root'
PASSWORD='123456'
DB_URL='mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)

#创建数据库引擎
engine=create_engine(DB_URL)

#测试数据库连接
# with engine.connect() as conn:
#     res=conn.execute('select 1')
#     print(res.fetchone())


#第一步:创建一个基类(所有ORM中的O,对象模型的超级父类
Base=declarative_base(engine)

#部门和员工之间,是一种典型的一(主)对多(从)
class Detp(Base):
    __tablename__='t_dept'
    deptno=Column(Integer,primary_key=True) #部门编号
    dname=Column(String(255)) #部门名字
    city=Column(String(50)) #城市
    #代表当前部门下的所有员工列表,这种 写法不是最好的,最优的写法只要其中一个对象中关联就可以
    #emps=relationship("Emp") #参数必须是另外一个相关联的类名

    def __str__(self):
        return "DEPT:<部门编号:{},部门名字:{}>".format(self.deptno,self.dname)
#员工表
class Emp(Base):
    __tablename__='t_emp'
    emp_no=Column(Integer,primary_key=True)
    ename=Column(String(50))
    job=Column(String(50))
    hire_date=Column(String(50))
    sal=Column(String(50))
    '''
    外键的删除选项
    1.RESTRICT:若子表中有父表对应的关键数据,删除父表对应数据,会阻止删除。默认项
    2,NO ACTION: 在MYSQL中,同RESTRICT.
    3.CASCADE: 级联删除
    4.SET NULL: 父表对应数据库被删除时,子表对应数据项会被设置为NULL
    '''
    dept_no=Column(Integer,ForeignKey('t_dept.deptno',ondelete='RESTRICT'))#外键

    #对列表进行懒加载  追加
    dept=relationship('Detp',backref=backref('emps',lazy='dynamic'),lazy='select') #backref='emps' 反向关联

    def __str__(self):
        return "EMP:<员工编号;{},员工姓名:{}>".format(self.emp_no,self.ename)


session=sessionmaker(engine)()

def test_lazy():
    d=session.query(Detp).filter(Detp.deptno==1)
    # print(type(d))
    # print('===================')
    # print(d)
    # print('===================')
    # print(d.first())#执行sql
    result=d.first() #当前对象是一个AppendQuery对象:可以进行追加操作
    print(result)

    #追加操作
    # e=Emp(ename='杨文祥',job='python开发工程师',hire_date=date(2022,10,9),sal=15000)
    # result.emps.append(e)
    # session.commit()

    #排序
    p=result.emps.order_by(Emp.sal).all()
    for i in p:
        pass
        #print(i)
    #过滤
    # p=result.emps.filter(Emp.emp_no >1).all()
    # print(p)
if __name__ == '__main__':
    test_lazy()

四、Flask-SQLAIchemy

  • 介绍:Flask-SQLAlchemy的使用_对SQLAlchemy进行了封装和优化:
  1. Flask-SQLAlchemy是Flask框架的一个插件,
  2. Flask-SQLAlchemy是对SQLAlchemy进行了一个简单的封装的一个插件,
  3. 使得我们在Flask中使用sqlalchemy更加的简单。

1、在templates下配置HTML文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试flask的sqlalchemy</title>
</head>
<body>
<a href="/add1?name=zs&pwd=123">新增操作</a>
<a href="/query?id=5">查询操作</a>
<a href="/update?id=3">修改操作</a>
<a href="/delter?id=4">删除操作</a>
</body>
</html>

2、在flask项目里面配置

  • 在不同的视图函数里实现不同的功能。
  • 在客户端里通过调用不同的参数,来实现函数的功能。
from flask import Flask,request,render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)

# 数据库的配置变量
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'test'
USERNAME = 'root'
PASSWORD = '123456'
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

# 把链接数据库的参数设置到app中
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
# 关闭追踪数据库的修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 1, 创建数据库连接
db = SQLAlchemy(app)
# 2创建模型类
class User(db.Model): #model的作用是定义出对象模型,一般都是和数据库里表对应,一个表一个model类,表里面的字段对应model类的属性,
    __tablename__ = 't_user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    uname = db.Column(db.String(20))
    pwd = db.Column(db.String(20))

    def __repr__(self):
        return "<User:id=%s,uname=%s,pwd=%s>" % (self.id, self.uname, self.pwd)

# 创建表
db.create_all()
@app.route('/')
def hello_world():  # put application's code here
    return render_template('1.html')

#新增操作
@app.route('/add1')
def add1():
    name=request.args.get('name')
    pwd=request.args.get('pwd')

    # print(name)
    # print(pwd)
    #插入到数据库t_user表
    user=User(uname=name,pwd=pwd)
    db.session.add(user)
    db.session.commit()
    return '添加成功,添加的数据是:姓名:{},密码:{}'.format(name,pwd)

#查询操作
@app.route('/query')
def query():
    id=request.args.get('id')
    user=db.session.query(User).filter(User.id==id).first()
    print(user)
    return '查询成功!姓名:{},密码:{}'.format(user.uname,user.pwd)

#修改操作
@app.route('/update')
def update():
    id=request.args.get('id')
    user=db.session.query(User).filter(User.id==id).first()
    #把id=3的姓名改成root,密码改成123456
    user.uname='root'
    user.pwd='123456'
    db.session.commit()
    return '修改成功'

#删除
@app.route('/delter')
def delter():
    id=request.args.get('id')
    user=db.session.query(User).filter(User.id==id).first()
    if user:
        db.session.delete(user)
        db.session.commit()

    return '删除成功!'
if __name__ == '__main__':
    app.run()

客户端界面
在这里插入图片描述

3、Flask-SQLAlchemy和alembic结合

  • alembic的主要作用是在创建好表后,要新增或者删除字段时。
  • 不需要像以前先把创建好的表删了,在创建新的表
  • 可以直接通过删除、新增字段,就可以在表里面实现

步骤一 、 pip install alembic 安装alembic

步骤二、 新建一个py (config.py) 文件用来配置连接数据库的

HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'alembic_test'
USERNAME = 'root'
PASSWORD = '123456'
DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

# 把链接数据库的参数设置到app中
SQLALCHEMY_DATABASE_URI= DB_URL
# 关闭追踪数据库的修改
SQLALCHEMY_TRACK_MODIFICATIONS= False

步骤三、注册config.py到flask项目

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config
app = Flask(__name__)
#把配置加载到flask项目中
app.config.from_object(config)
db=SQLAlchemy(app)

#创建学生表
class User(db.Model): #model的作用是定义出对象模型,一般都是和数据库里表对应,一个表一个model类,表里面的字段对应model类的属性,
    __tablename__ = 't_user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    uname = db.Column(db.String(20))
    pwd = db.Column(db.String(20))
    #增加字段
    age=db.Column(db.Integer)
    adress=db.Column(db.String(50))

    #再次增加字段
    sal=db.Column(db.String(5))
@app.route('/')
def hello_world():  # put application's code here
    return 'Hello World!'


if __name__ == '__main__':
    app.run()

步骤四、 创建一个仓库

  • 如果是在pycharm终端上执行的话,可以直接输入 alembic init 仓库的名字(需自定义)
  • 如果在命令行窗口执行 ,先进入虚拟环境 (前面创建用来写flask项目的虚拟环境),然后cd到当前项目

步骤五、修改配置件alembic.ini和env.py

  1. 修改配置件alembic.ini 使其连接到自己的数据库
sqlalchemy.url = mysql+pymysql://root:123456@localhost:3306/alembic_test?charset=utf8mb4
  1. 修改配置件env.py 使其把当前项目路径加入到path中
import os
import sys
#把当前项目路径加入到path中
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import app
target_metadata = app.db.Model.metadata

步骤六、自动生成迁移文件
将当前模型中的状态生成迁移文件。

  • 在终端执行 alembic revision --autogenerate -m “提示信息” (提示信息可以随便写)

步骤七、映射到数据库中
使用alembic upgrade head将刚刚生成的迁移文件,真正映射到数据库中。

  • 在终端执行 alembic upgrade head
  • 执行完这一步,在数据库看到的表就是修改结构了的了

若以后在修改表的结构重复 6,7步骤即可。

总结

以上就是本章对flask_sqlalchemy的学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值