Welcome to kimi's blog

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在其中添加数据时,自动触发

使用内置信号的步骤

  1. 写一个函数
  2. 绑定内置信号
  3. 等待被触发
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

image-20230407203808534

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框架,为了方便快速操作数据库,使用关系映射flaskfastapi中使用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可以实现类似于djangopython 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项目演示

  1. 创建数据库 movie
  2. pycharm打开项目
  3. 在models中,注释,解开注释,右键执行,迁移表
  4. 在models中恢复原来的
  5. 在命令行中python manage.py runserver运行项目
  6. 访问前台和后台
posted @   魔女宅急便  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
Title

目录导航

点击右上角即可分享
微信分享提示