Flask之信号/sqlalchemy/flask-sqlalchemy/flask-migrate/scoped_session
信号
Flask框架
中的信号基于blinker(安装这个模块 pip install blinker)
,其主要就是让开发者可是在flask
请求过程中定制一些用户行为 ,flask 和django都有信号
观察者模式,又叫发布-订阅(Publish//Subscribe) 23 种设计模式之一
信号:signial , 并发编程中是信号量Semaphore
信号的使用场景
# 比如:用户表新增一条记录,就记录一下日志
-方案一:在每个增加后,都写一行代码 ---》后期要删除,比较麻烦
-方案二:使用信号,写一个函数,绑定内置信号,只要程序执行到这,就会执行这个函数
# 内置信号: flask少一些,django多一些
request_started = _signals.signal('request-started') # 请求到来前执行
request_finished = _signals.signal('request-finished') # 请求结束后执行
before_render_template = _signals.signal('before-render-template') # 模板渲染前执行
template_rendered = _signals.signal('template-rendered') # 模板渲染后执行
got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行
request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 应用上下文执行完毕后自动执行(无论成功与否)
appcontext_pushed = _signals.signal('appcontext-pushed') # 应用上下文push时执行
appcontext_popped = _signals.signal('appcontext-popped') # 应用上下文pop时执行
message_flashed = _signals.signal('message-flashed') # 调用flask在其中添加数据时,自动触发
使用内置信号的步骤
- 写一个函数
- 绑定内置信号
- 等待被触发
from flask import signals
1 写一个函数
def test(*args,**kwargs):
print(args)
print(kwargs)
print('我执行了')
2.内置信号很多,随意绑定一个:模板渲染前
signals.before_render_template.connect(test)
3.等待被触发
自定义信号
from flask.signals import _signals
# 1.定义信号
session_set = _signals.signal('session_set')
# 2.写一个函数
def task(*args,**kwargs):
print(args)
print(kwargs)
print('session设置值了')
# 3.绑定琉璃自定义的信号
session_set.connect(task)
# 4. 触发信号的执行---我们做的
session_set.send('kimi') # 触发信号执行
# django中使用信号
https://www.cnblogs.com/liuqingzheng/articles/9803403.html
django信号
Model signals # 模型层
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals # 迁移命令
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response signals # 请求
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Database Wrappers # 数据库
connection_created # 创建数据库连接时,自动触发
# django中使用内置信号
1.写一个函数
def callBack(*args, **kwargs):
print(args)
print(kwargs)
2.绑定信号
# 方式一
post_save.connect(callBack)
# 方式二
formfrom django.db.models.signals import pre_save
from django.dispatch import receiver
@receiver(pre_save)
def my_callback(sender, **kwargs):
print("对象创建成功")
print(sender)
print(kwargs)
3.等待触发
flask-script
django启动项目命令:python manage.py runserver
flask启动项目命令
# 首先注意两个模块的版本
Flask===2.2.2 Flask_Script==2.0.3
# 借助于:flask-script 实现
1.安装
pin install flask_script
2.修改代码
from flask_script import Manager
manager=Manager(app) # app注册
manager.run()
3.命令行启动项目
python manage.py runserver
#Flask 自定制命令
1.简单自定制命令
@manager.command
def custom(arg):
# 命令的代码,比如:初始化数据库, 有个excel表格,使用命令导入到mysql中
print(arg)
# >python manage.py custom kimi---》kimi
2.复杂一些的自定制命令
@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
# python run.py cmd -n kimi -u xxx
# python run.py cmd --name kimi --url uuu
print(name, url)
# django 中如何自定制命令----git 项目django-admin-vue--git项目中可以借鉴
sqlalchemy
sqlalchemy介绍
flask
没有ORM框架,为了方便快速操作数据库,使用关系映射,flask
和fastapi
中使用sqlalchemy
居多。SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API(数据库api的规范)之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果
# 安装
pip3.8 install sqlalchemy
#了解
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件
pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
更多:http://docs.sqlalchemy.org/en/latest/dialects/index.html
sqlalchemy快速使用
# 先不是orm,而是原生sql
# 第一步:导入
from sqlalchemy import create_engine
# 第二步:生成引擎对象
engine = create_engine(
"mysql+pymysql://root@127.0.0.1:3306/cnblogs" 没有密码
"mysql+pymysql://root:123@127.0.0.1:3306/end?charset=utf8 " # 有密码的root
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第三步:使用引擎获取连接,操作数据库
conn = engine.raw_connection()
cursor=conn.cursor()
cursor.execute('select * from aritcle')
print(cursor.fetchall())
sqlalchemy创建表和操作数据
# 第一步:导入
from sqlalchemy import create_engine
import datetime
from sqlalchemy.ext.declarative import declarative_base # sqlalchemy2.0之后从orm导入
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
# 第二步:执行declarative_base,得到一个类
Base = declarative_base()
# 第三步:继承生成的Base类
class User(Base):
# 第四步:写字段
id = Column(Integer, primary_key=True) # 生成一列,类型是Integer,主键
name = Column(String(32), index=True, nullable=False) # name列varchar32,索引,不可为空
email = Column(String(32), unique=True)
# datetime.datetime.now不能加括号,加了括号,以后永远是当前时间
ctime = Column(DateTime, default=datetime.datetime.now)
# extra = Column(Text, nullable=True)
# 第五步:写表名 如果不写以类名为表名
__tablename__ = 'users' # 数据库表名称
# 第六步:建立联合索引,联合唯一
__table_args__ = (
UniqueConstraint('id', 'name', name='uix_id_name'), # 联合唯一
Index('ix_id_name', 'name', 'email'), # 索引
)
class Book(Base):
__tablename__ = 'books'
id = Column(Integer, primary_key=True)
name = Column(String(32))
# 第七步:把表同步到数据库中
# 不会创建库,只会创建表
engine = create_engine(
"mysql+pymysql://root@127.0.0.1:3306/aaa",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 把表同步到数据库 (把被Base管理的所有表,都创建到数据库)
Base.metadata.create_all(engine)
# 把所有表删除
# Base.metadata.drop_all(engine)
sqlalchemy快速插入数据
sqlclchemy是orm框架跟其他web框架没有必然联系,可以独立使用(执行原生sql),在创建表和删除表的时候,注意不能创建数据库,需要手动创建数据库,也不能直接在模型表修改字段(增加和删除)。
使用orm插入数据
# 使用orm插入
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Book
# 第一步:生成engine对象
engine = create_engine(
"mysql+pymysql://root:123@127.0.0.1:3306/flask_db",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步,拿到Session类并将engine传入
Session = sessionmaker(bind=engine)
# 第三步,拿到session对象,相当于连接对象(会话)
session = Session()
# 第四步 增加数据
book = Book(name='人生之路',)
session.add(book)
session.commit()
session.close()
scoped_session线程安全
添加数据时,使用的都是session对象,session对象放在视图函数里面,每次都会得到一个新的session对象,浪费资源;如果做成全局session对象,会有并发安全问题(数据错乱),于是sqlalchemy就使用scoped_session解决了这个问题。
from sqlalchemy.orm import scoped_session,sessionmaker
from sqlalchemy import create_engine
# 第一步:生成engine对象
engine = create_engine(
"mysql+pymysql://root:123@127.0.0.1:3306/flask_db",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步,拿到Session类,传入engine
Session = sessionmaker(bind=engine)
# 线程不安全----》因为全局都用一个session对象,会有并发安全问题,于是sqlalchemy就使用scoped_session解决了这个问题
# session = Session()
""" 还是做成线程且安全,如何做?
内部使用了local对象,取当前线程的session,如果有直接使用,
如果没有直接创建一个,放到local中
session是scoped_session的对象"""
# session对象,不是Session的对象,但是它有Session的所有方法
session = scoped_session(Session) # 以后全局使用session即可,线程是安全的
类中添加装饰器
# session 是 scoped_session 的对象,类上没有属性和方法,但是,用的时候,确实用
session = scoped_session(Session)
def test():
print('我是test')
def wrapper(func):
def inner(*args,**kwargs):
res = func(*args,**kwargs)
res.name='kimi'
res.test=test
return res
return inner
@wrapper # 语法糖会把Person当参数传入到装饰器中 Person=wrapper(Person)
class Person:
pass
p= Person()
print(p.name) # kimi
p.test() # 我是test
基本增删改查
filter/filter_by/add/add_all/update/delete/
# 增,删,改
# 查 基本查询和高级查询
from sqlalchemy.orm import sessionmaker,scoped_session
from sqlalchemy import create_engine
from sqlalchemy.sql import text
from models import User,Book
engine = create_engine( "mysql+pymysql://root:123@127.0.0.1:3306/flask_db")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
# 1. 增加:add 与add_all
# user = User(name='kimi',email='123@qq.com',extra='杭州西湖')
# session.add(user)
# user = User(name='kiki',email='134@qq.com',extra='江苏南京')
# user1 = User(name='rose',email='666@qq.com',extra='山西太原')
# book = Book(name='红楼梦')
# session.add_all([user,user1,book])
# session.commit()
# session.close()
# 2.查 filter(写条件) filter_by(等于值)
# filter
# 2.1 session.query(User) 中写表模型,可以写多个表模型(连表操作) 相当于select * from User;
# 2.2 filter 过滤条件,必须写表达式 == >= <= != select * from user where user.id=1
# 2.3 all:普通列表 first
# user = session.query(User).filter(User.name=='kimi').first()
# user = session.query(User).filter(User.name!='kimi').all()
# user = session.query(User).filter(User.id>1).all()
# print(user)
# filter_by 直接写等式 不能写成 User.name = 'lqz'
# user = session.query(User).filter_by(name='kimi').first()
# user = session.query(User).filter_by(id=1).first()
# print(user)
# # 3 删除(查到才能删) filter或filter_by查询的结果 不要all或first出来, .delete()即可
# res = session.query(User).filter(User.id==1).delete()
# res = session.query(User).filter_by(id=3).delete()
# session.commit()
# print(res) # 影响的行数
# 4 修改(查到才能改)
# 方式一:update修改
# res = session.query(User).filter_by(id=1).update({'name':'rose'})
# session.commit()
# 方式二,使用对象修改
# res = session.query(User).filter_by(id=1).first()
# res.name='kimi'
# session.add(res) # add 如果有主键,就是修改,如果没有主键就是新增
# session.commit()
# print(res)
1. 基本增删改查和高级查询
filter/filter_by/ 占位符:name :value /原生sql:from_statement
# 4 查询: filer:写条件 filter_by:等于的值
# 4.1 查询所有 是list对象
# res = session.query(User).all() # 是个普通列表
# print(type(res)) # <class 'list'>
# print(len(res))
# 4.1.1 只查询某几个字段
# select name as xx,email from user;
# res = session.query(User.name.label('xx'),User.email)
# print(res) # 原生sql语句
# print(res.all()) # [('kiki', '134@qq.com'), ('kimi', '123@qq.com')]
# for item in res.all():
# print(item[0]) # kiki,kimi
# 4.1.2 filter传的是表达式,filter_by传的是参数
# res = session.query(User).filter(User.name == "kimi").all()
# res = session.query(User).filter(User.name != "kimi").all()
# res = session.query(User).filter(User.name != "kimi", User.email == '134@qq.com').all() # django 中使用 Q
# res = session.query(User).filter_by(name='kiki').all()
# res = session.query(User).filter_by(name='kimi',email='123@qq.com').all()
# print(res)
# 4.2 取一个 all了后是list,list 没有first方法
# res = session.query(User).first()
# print(res)
# 4.3 查询所有,使用占位符(了解) :value :name
# select * from user where id <3 or name=kimi
# res = session.query(User).filter(text("id<:value or name=:name")).params(value=3, name='kimi').all()
# print(res)
# 4.4 自定义查询(了解)
# from_statement 写纯原生sql
# res=session.query(Book).from_statement(text("SELECT * FROM users where email=:email")).params(email='123@qq.com').all()
# res=session.query(User).from_statement(text("SELECT * FROM users where email=:email")).params(email='123@qq.com').all()
# print(type(res[0])) # 是book的对象,但是查的是User表 不要这样写query(Book)
# print(res[0].name) #
高级查询: and between in ~非 having and or 通配符like 分页 order_by排序
""" 高级查询"""
# 条件
# 表达式,and条件连接
# res = session.query(User).filter(User.id>1,User.name=='kiki').all()
# print(res)
# between
# res = session.query(User).filter(User.id.between(1,3)).all()
# res = session.query(User).filter(User.id.between(1,3),User.name=='kimi').all()
# print(res) # [kimi]
# in
# res = session.query(User).filter(User.id.in_([1,3,4])).all()
# print(res)
# ~非,除。。外
# res = session.query(User).filter(~User.id.in_([1,3,4])).all()
# print(res)
# 二次筛选
# res = session.query(User).filter(~User.id.in_(session.query(User.id).filter_by(name='kimi'))).all()
# print(res)
# and or条件 # or_包裹的都是or条件,and_包裹的都是and条件
from sqlalchemy import and_, or_
# res = session.query(User).filter(and_(User.id >= 1, User.name == 'kimi')).all() # and条件
# res = session.query(User).filter(User.id >= 1, User.name == 'kimi').all() # 等同与上面
# res = session.query(User).filter(or_(User.id >=1, User.name == 'kiki')).all() # 等同与上面
# res = session.query(User).filter(
# or_(
# User.id >= 1,
# and_(User.name == 'kiki',User.id>2), # 等同与上面
# User.extra != '',)).all()
# print(res)
# 通配符,以e开头,不以e开头
# res = session.query(User).filter(User.email.like('%@%')).all()
# select user.id from user where user.name not like e%;
# res = session.query(User).filter(~User.name.like('e%')).all()
# 分页
# 一页2条,查第5页
# res = session.query(User)[2*5:2*5+2]
# 排序,根据name降序排列(从大到小)
# res = session.query(User).order_by(User.email.desc()).all() # 降序
# res = session.query(Book).order_by(Book.id.desc()).all()
# res = session.query(Book).order_by(Book.id.asc()).all()
# 第一个条件重复后,再按第二个条件升序排
# res = session.query(User).order_by(User.name.desc(),User.id.asc())
# res = session.query(User).order_by(User.name.desc(), User.id.asc()).all()
高级查询之分组查询(max/sum/min)
# 分组查询 聚合函数
from sqlalchemy.sql import func
# res = session.query(User).group_by(User.extra) # 如果是严格模式,就报错
# 分组之后取最大id,id之和,最小id 和分组的字段
# res = session.query(
# User.extra,
# func.max(User.id),
# func.sum(User.id),
# func.min(User.id),
#
# ).group_by(User.extra)
# for i in res:
# print(i)
# having
# select max(id),sum(id),min(id) from user group by user.extra having id_max>2;
res = session.query(
func.max(User.id),
func.sum(User.id),
func.min(User.id),
).group_by(User.extra).having(func.max(User.id)>2).all()
print(res)
2. 原生sql
方式一:raw_connection()
# 第一步:导入
from sqlalchemy import create_engine
# 第二步:生成引擎对象
engine = create_engine(
"mysql+pymysql://root:123@127.0.0.1:3306/flask_db",
max_overflow=0, # 超过连接池大小外最多创建的连接
pool_size=5, # 连接池大小
pool_timeout=30, # 池中没有线程最多等待的时间,否则报错
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第三步:使用引擎获取连接,操作数据库
conn = engine.raw_connection()
cursor=conn.cursor()
cursor.execute('select * from books')
print(cursor.fetchall())
方式二
from models import User, Book
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/flask_db")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
# 2.0.9 版本需要使用text包裹一下,原来版本不需要
# cursor = session.execute(text('select * from users'))
# result = cursor.fetchall()
# print(result)
cursor = session.execute(text('insert into books(name) value(:name)'),params={'name':'茶花女'})
session.commit()
print(cursor.lastrowid) # 影响的第几行
session.close()
3. django中执行原生sql
# 选择的查询基表Book.objects.raw ,只是一个傀儡,正常查询出哪些字段,都能打印出来
def index(request):
# books = Book.objects.raw('select * from app01_book where id=1') # RawQuerySet 用起来跟列表一样 book对象
# books = Publish.objects.raw('select * from app01_book where id=1') # RawQuerySet 用起来跟列表一样 publish对象
# print(books[0])
# print(type(books[0]))
# # for book in books:
# # print(book.name)
# # print(books[0].name)
# print(books[0].addr) #也能拿出来,但是是不合理的
res = Book.objects.raw('select * from app01_publish where id=1') # RawQuerySet 用起来跟列表一样
print(res[0])
print(type(res[0]))
print(res[0].name)
# book 没有addr,但是也打印出来了
print(res[0].addr)
return HttpResponse('ok')
一对多--单表操作
不管是一对一(也是一对多,但是对其中键设置了unique),一对多,还是多对多(中间表与其他两个表是一对多关系,本质也是一对多关系),本质就是一种外键关系。
表模型
# 一对多关系
from sqlalchemy import create_engine
import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
from sqlalchemy.orm import relationship
# 第二步:执行declarative_base,得到一个类
Base = declarative_base()
class Hobby(Base):
__tablename__ = 'hobby'
id = Column(Integer, primary_key=True)
caption = Column(String(50), default='篮球')
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String(32), index=True, nullable=True)
# hobby指的是tablename而不是类名
# 关联字段写在多的一方,写在Person中,跟hobby表中id字段做外键关联
hobby_id = Column(Integer, ForeignKey("hobby.id"))
# relationship跟数据库无关,不会新增字段,只用于快速链表操作
# 基于对象的跨表查询:就要加这个字段,取对象 person.hobby pserson.hobby_id
# 类名,backref用于反向查询
hobby = relationship('Hobby', backref='pers') # 如果有hobby对象,拿到所有人 hobby.pers
def __repr__(self):
return self.name
engine = create_engine("mysql+pymysql://root@127.0.0.1:3306/flask_db", )
# 把表同步到数据库 (把被Base管理的所有表,都创建到数据库)
Base.metadata.create_all(engine)
# 把所有表删除
# Base.metadata.drop_all(engine)
新增数据
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker,scoped_session
from models1 import Hobby,Person
engine=create_engine("mysql+pymysql://root@127.0.0.1:3306/flask_db")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
# 一对多新增
# 不新增外键,单添加单表的数据
# hobby = Hobby(caption='羽毛球')
# session.add(hobby)
# person = Person(name='kimi')
# session.add(person)
# session.commit()
# 新增数据并建立外键关系
# hobby = session.query(Hobby).filter(Hobby.caption=='羽毛球').first()
# person = Person(name='kiki',hobby_id = hobby.id) # 通过relationship
# person = Person(name='rose',hobby_id = 1) # 通过关联的id号
# session.add(person)
# session.commit()
基于对象的查询
# 支持按对象的增加方式,必须加relationship 做关联
# 方式一
# hobby = session.query(Hobby).filter(Hobby.caption=='羽毛球').first()
# person = Person(name='tony',hobby=hobby)
# 方式二
# hobby = Hobby(caption='棒球') # 表中暂时没有
# person = Person(name='jenny',hobby=hobby)
# session.add_all([person,hobby])
# session.commit()
# print(hobby)
## 基于对象的跨表查询 .
# 正向查询
# person = session.query(Person).filter(Person.name=='kimi').first()
# print(person.hobby_id) # 1
# print(person.hobby) # Hobby 的对象
# print(person.hobby.id) # 1
# print(person.hobby.caption) # 羽毛球
# 反向查询
hobby = session.query(Hobby).filter(Hobby.id==1).first()
print(hobby.pers) # pers是relationship里面反向查询的关联字
多对多--单表操作
表模型
# 一对多关系
from sqlalchemy import create_engine
import datetime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
from sqlalchemy.orm import relationship
# 第二步:执行declarative_base,得到一个类
Base = declarative_base()
# 多对多
# 中间表 手动创建
class Boy2Girl(Base):
__tablename__ = 'boy2girl'
id = Column(Integer, primary_key=True, autoincrement=True)
girl_id = Column(Integer, ForeignKey('girl.id'))
boy_id = Column(Integer, ForeignKey('boy.id'))
class Girl(Base):
__tablename__ = 'girl'
id = Column(Integer, primary_key=True)
name = Column(String(64), unique=True, nullable=False)
def __str__(self):
return self.name
def __repr__(self): # 生成列表的时候会触发__repr__方法
return self.name
class Boy(Base):
__tablename__ = 'boy'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(64), unique=True, nullable=False)
# 与生成表结构无关,仅用于查询方便,放在哪个单表中都可以
# 方便快速查询,写了这个字段,相当于django 的manytomany,快速使用基于对象的跨表查询
girls = relationship('Girl', secondary='boy2girl', backref='boys')
def __str__(self):
return self.name
def __repr__(self):
return self.name
engine = create_engine("mysql+pymysql://root@127.0.0.1:3306/flask_db", )
# 把表同步到数据库 (把被Base管理的所有表,都创建到数据库)
Base.metadata.create_all(engine)
# 把所有表删除
# Base.metadata.drop_all(engine)
增加和基于对象的跨表查询
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker,scoped_session
from models2 import Girl,Boy2Girl,Boy
engine=create_engine("mysql+pymysql://root:123@127.0.0.1:3306/flask_db")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
# 新增
# 1 笨办法新增
# girl = Girl(name='kiki')
# boy = Boy(name='tom')
# session.add_all([girl,boy])
# session.add(Boy2Girl(girl_id=1,boy_id=1)) # 先增加boy和girl表,再添加Boy2Girl表关系
# session.commit()
# 2. 使用relationship
# boy = Boy(name='fy') # name必须要为表中没有
# boy.girls=[Girl(name='刘亦菲'),Girl(name='孟子义')]
# session.add(boy)
# session.commit()
# 基于对象的跨表查询
# 正向
# boy = session.query(Boy).filter(Boy.name=='fy').first()
# print(boy.girls)
girl = session.query(Girl).filter(Girl.name=='刘亦菲').first()
print(girl.boys)
# 如果没有relationship,纯自己操作
连表查询
关联关系,基于连表的跨表查询
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker,scoped_session
from models2 import Boy,Girl,Boy2Girl
engine=create_engine("mysql+pymysql://root:123@127.0.0.1:3306/flask_db")
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
from models1 import Person,Hobby
### 关联关系,基于连表的跨表查询
# 链表操作
# select * from person,hobby where person.hobby_id=hobby.id;
# res = session.query(Person,Hobby).filter(Person.hobby_id==Hobby.id).all()
# print(res)
# 自己连表查询
# join表,默认是inner join,自动按外键关联
# select * from Person inner join Hobby on Person.hobby_id=Hobby.id;
# res = session.query(Person).join(Hobby).all()
# print(res)
#isouter=True 外连,表示Person left join Favor,没有右连接,反过来即可
# select * from Person left join Hobby on Person.hobby_id=Hobby.id;
# select * from Person inner join Hobby on Person.hobby_id=Hobby.id;
# res = session.query(Person).join(Hobby,isouter=True).all()
# 没有right join,通过这个实现
# res = session.query(Hobby).join(Person,isouter=True).all()
# print(res)
# # 自己指定on条件(连表条件),第二个参数,支持on多个条件,用and_,同上
# select * from Person left join Hobby on Person.id=Hobby.id;
# res = session.query(Person).join(Hobby, Person.hobby_id == Hobby.id, isouter=True) # sql本身有问题,只是给你讲, 自己指定链接字段
# 右链接
# print(res)
# 多对多关系连表
# 多对多关系,基于链表的跨表查
#方式一:直接连
# res = session.query(Boy, Girl,Boy2Girl).filter(Boy.id == Boy2Girl.boy_id,Girl.id == Boy2Girl.girl_id).all()
# 方式二:join连
res = session.query(Boy).join(Boy2Girl).join(Girl).filter(Person.id>=2).all()
print(res)
类当作装饰器/装饰类的装饰器
# 1.装饰类的装饰器,加在类上的装饰器
# def speak():
# print('说话了')
#
#
# def wrapper(func):
# def inner(*args, **kwargs):
# res = func()
# res.name = 'lqz'
# res.speak = speak
# return res
#
# return inner
#
#
# @wrapper # 语法糖会把Person当参数传入到装饰器中 Person=wrapper(Person)
# class Person:
# pass
#
#
# p = Person()
#
# print(p.name)
# p.speak()
# 2. 类作为装饰器来用
class Wrapper():
def __init__(self,func):
self.func=func
def __call__(self, *args, **kwargs):
# 前面加代码
print('类中方法')
res = self.func(*args, **kwargs)
# 后面加代码
return res
@Wrapper # add=Wrapper(add) -->触发Wrapper的__init__方法---》add现在是wrapper的对象
def add():
print('add')
add() # 对象加括号触发类的__call__
flask-sqlalchemy使用
集成到flask中,使用直接sqlalchemy,而第三方模块flask-sqlalchemy
可以帮我们快速集成到flask中。
sqlalchemy集成到flask
# 视图文件
from flask import Flask
from models import Book
from session_sql import session
app = Flask(__name__)
@app.route('/')
def index():
session.add(Book(name='回忆'))
session.commit()
session.close()
return '新增记录'
if __name__ == '__main__':
app.run()
# session_sql文件
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
engine = create_engine('mysql+pymysql://root:123@127.0.0.1:3306/flask_db')
Session = sessionmaker(bind=engine)
session = scoped_session(Session)
flask-sqlalchemy集成到flask
# 下载 flask-sqlalchemy
# 使用
1.导入
form flask_sqlalchemy import SQLAlchemy
2.实列化得到对象
db = SQLAlchemy()
3.将db注册到app中
db.init_app(app)
4.视图函数中使用session
全局的db.session # 线程安全的
5.models.py 中继承 Model
db.Model
6.写字段
username = db.Column(db.String(80), unique=True, nullable=False)
7.配置文件中加入
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root@127.0.0.1:3306/ddd?charset=utf8"
SQLALCHEMY_POOL_SIZE = 5
SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = -1
# 追踪对象的修改并且发送信号
SQLALCHEMY_TRACK_MODIFICATIONS = False
manage.py文件
# manage.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_pyfile('settings.py')
db= SQLAlchemy()
db.init_app(app)
@app.route('/')
def index():
from models import Book
db.session.add(Book(name='回忆'))
db.session.commit()
db.session.close()
return '新增记录'
if __name__ == '__main__':
app.run()
# model.py
class User(db.Model):
# 第四步:写字段
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), index=True, nullable=False)
email = db.Column(String(32), unique=True)
ctime = db.Column(db.DateTime, default=datetime.datetime.now)
extra = db.Column(db.Text, nullable=True)
# 第五步:写表名 如果不写以类名为表名
__tablename__ = 'users' # 数据库表名称
class Book(db.Model):
__tablename__ = 'books'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
def __str__(self):
return self.name
flask-migrate
只要模型表发生变化,都会有记录,自动同步到数据库中,原生的sqlalchemy,不支持修改表的,但是flask-migrate可以实现类似于django的python manage.py makemigrations
记录和python manage.py migrate
同步到数据库
# flask:2.2.2 flask-script:2.0.3
# 1.安装 依赖于flask-script
pip install flask-migrate==2.7.0
# 2.在app所在的py文件中
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
# flask-script的使用
manager = Manager(app) # 第一步:初始化出flask_script的manage
Migrate(app, db) # 第二步:使用flask_migrate的Migrate 包裹一下app和db(sqlalchemy对象)
# 第三步:把命令增加到flask-script中去
manager.add_command('db', MigrateCommand) # 多出三个命令 init migrate upgrade
manager.run() # 以后使用python manage.py runserver 启动项目
# 3. 以后第一次执行一下
python manage.py db init # 生成一个migrations文件夹,里面以后不要动,记录迁移的编号
# 4.模型表
在models.py 写表,加字段,删字段,改参数
# 5.只需要执行
python manage.py db migrate # 记录
python manage.py db upgrade # 真正的同步进去
flask项目演示
- 创建数据库 movie
- pycharm打开项目
- 在models中,注释,解开注释,右键执行,迁移表
- 在models中恢复原来的
- 在命令行中python manage.py runserver运行项目
- 访问前台和后台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!