flask基础fifth,flask-script, 增删改查,flask-SQLAlchemy

一、多app应用

  多个app实例(启用)

from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask, current_app
app1 = Flask('app01')
app2 = Flask('app02')

@app1.route('/index')
def index():
    return "app01"

@app2.route('/index2')
def index2():
    return "app2"

# http://www.oldboyedu.com/index
# http://www.oldboyedu.com/sec/index2
dm = DispatcherMiddleware(app1, {
    '/sec': app2,
})

if __name__ == "__main__":
    run_simple('localhost', 5000, dm)

#请求来了,会执行dm()--->__call__

 

二、flask-script(制定命令)

  1 模拟出类似django的启动方式:python manage.py runserver
  2 pip install flask-script
  3 把excel的数据导入数据库,定制个命令,去执行(openpyxl)
      python manage.py insertdb -f xxx.excel1 -t aa            (从excel1中读取数据插入到aa表里面,-f就是from , -t就是to)
    
  4 使用

      -方式一:python manage.py runserver

from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager=Manager(app)
if __name__ == '__main__':
    manager.run()

#此时执行命令就是在终端输入python 脚本名字 runserver

    ` -方式二:自定制命令

from flask import Flask
    from flask_script import Manager
    app = Flask(__name__)
    manager=Manager(app)

#自定义命令
@manager.command
def custom(arg):
    print(arg)
    #此时执行方法就是:python manage.py custom 123(传入的参数)

@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
    '''
    自定义命令(-n也可以写成-name)
    执行:Python manage.py cmd -n wmt -u http://www.baidu.com
    执行:python manage.py cmd --name wmt --url http://www.baidu.com
    '''
    print(name, url)


if __name__ == '__main__':
        manager.run()`

  5 创建超级用户
  6 现在有很多条excel用户,批量导入到数据库中

      -navicate直接支持
      -脚本
      -flask-script

 

三、sqlachemy

  第三方orm框架(对象关系映射)
     -go语言中 :gorm,xorm
     -python中:django orm,sqlachemy,peewee ,django orm只能在django中用,不能单独用

 

  1 使用: pip install sqlachemy
  2 SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件

  3 补充:django orm反向生成models
      -python manage.py inspectdb > app/models.py

 

基本使用(原生sql)

import time
import threading
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine

# 第一步生成一个engine对象
engine = create_engine(
    "mysql+pymysql://root:123@127.0.0.1:3306/flask?charset=utf8",
    max_overflow=0,            # 超过连接池大小外最多创建的连接
    pool_size=5,               # 连接池大小
    pool_timeout=30,           # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1            # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
# 第二步:创建连接(执行原生sql)
conn = engine.raw_connection()
# 第三步:获取游标对象
cursor = conn.cursor()
# 第四步:具体操作
cursor.execute('select * from boy')

res=cursor.fetchall()
print(res)

# 比pymysql优势在,有数据库连接池

orm的使用:

  先创建表,以及建立一对多、多对多关系表

# 创建一个个类(需清楚继承谁,字段写法)
import datetime
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base

# 字段和字段属性
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index

# 制造了一个类,作为所有模型类的基类
Base = declarative_base()

class User(Base):
    __tablename__ = 'users'  # 数据库表名称(固定写法),如果不写,默认以类名小写作为表的名字
    id = Column(Integer, primary_key=True)  # id 主键
    # mysql中主键自动建索引:聚簇索引
    # 其他建建的索引叫:辅助索引
    name = Column(String(32), index=True, nullable=False)  # name列,索引列,不可为空
    email = Column(String(32), unique=True)  # 唯一
    #datetime.datetime.now不能加括号,加了括号,以后永远是当前时间
    ctime = Column(DateTime, default=datetime.datetime.now) # default默认值
    extra = Column(Text, nullable=True)

    #类似于djagno的 Meta
    __table_args__ = (
        UniqueConstraint('id', 'name', name='uix_id_name'), #id和name联合唯一,且取名为uix_id_name
        Index('ix_id_name', 'name', 'email'), #索引
     )

#一对多关系表
class hobby(Base):
  __tablename__='hobby'
  id = Column(Integer,primary_key=True)
  caption = Column(String(50),default='篮球')

class Person(Base):
  
__tablename__='hobby'
  nid = Column(Integer,primary_key=True)
  name =Column(String(32),index=True,nullable=True)
  #hobby指的是tablename而不是类名,uselist=False
  hobby_id = Column(Integer,ForeignKey("hobby.id")) #建立一对多关系,且需要建立在多的一方

#多对多
#多对多肯定有一张第三方表,如下面的boy2girl
class Boy2Girl(Base):
  
__tablename__='boy2girl'
  id = Column(Integer,primary_key=True,autocrement=True)
  girl_id =Column(Integer,ForeignKey("girl.id"))
  boy_id =Column(Integer,ForeignKey("boy.id"))
class Boy(Base):
  __tablename__='boy'
  
id = Column(Integer,primary_key=True)
  name =Column(String(64),index=True,nullable=True)

class Girl(Base):
  __tablename__='girl'
  id = Column(Integer,primary_key=True)
  name =Column(String(64),index=True,nullable=True)
# 创建表
def create_table():
    # 创建engine对象
    engine = create_engine(
        "mysql+pymysql://root:123@127.0.0.1:3306/aaa?charset=utf8",
        max_overflow=0,  # 超过连接池大小外最多创建的连接
        pool_size=5,  # 连接池大小
        pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
        pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    )
    # 通过engine对象创建表
    Base.metadata.create_all(engine)

# 删除表
def drop_table():
    # 创建engine对象
    engine = create_engine(
        "mysql+pymysql://root:123@127.0.0.1:3306/aaa?charset=utf8",
        max_overflow=0,  # 超过连接池大小外最多创建的连接
        pool_size=5,  # 连接池大小
        pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
        pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
    )
    # 通过engine对象删除所有表
    Base.metadata.drop_all(engine)

if __name__ == '__main__':
    create_table()
    #drop_table()

# 需要手动创建库
# sqlachemy不支持修改字段吗

  通过orm给表插入一条数据

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import User            # pycharm报错,不会影响我们
from sqlalchemy.orm import scoped_session

# 1 制作engine
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)

# 2 制造一个 session 类(会话)
Session = sessionmaker(bind=engine)    # 得到一个类
# 3 得到一个session对象
session=Session()

# 4 创建一个对象
obj1 = User(name="wmt")
# 5 把对象通过add放入
session.add(obj1)
# 6 提交
session.commit()

  线程安全(多线程情况下):

#基于scoped_session实现线程安全
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import User  
from sqlalchemy.orm import scoped_session

# 1 制作engine
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)

# 2 制造一个 session 类(会话)
Session = sessionmaker(bind=engine)    # 得到一个类
# 3 得到一个session对象(线程安全的session)
#现在的session已经不是session对象了
#线程安全,还是用的local
session = scoped_session(Session)

# 4 创建一个对象
obj1 = User(name="2008")
# 5 把对象通过add放入
session.add(obj1)
# session.aaa()
# 6 提交
session.commit()
session.close()

# 类不继承Session类,但是有该类的所有方法(是因为通过反射,一个个放进去的)

  orm的增删改

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import User,Person,Hobby
from sqlalchemy.orm import scoped_session
from sqlalchemy.sql import text
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)

Session = sessionmaker(bind=engine)
#线程安全
# session = scoped_session(Session)
session=Session()

#1 新增多个对象
obj=User(name='xxx')
obj2=User(name='yyyy')
obj3=User(name='zzz')
#新增同样对象
session.add_all([obj,obj2,obj3])
#新增不同对象
session.add_all([Person(name='lqz'),Hobby()])

#2 简单删除(查到删除)
res=session.query(User).filter_by(name='2008').delete()       #filter_by传的是参数
res=session.query(User).filter(User.id>=2).delete()       #filter传的是表达式
# 返回1,代表影响1行
print(res)

# 3 修改
res=session.query(User).filter_by(id=1).update({User.name:'ccc'})
res=session.query(User).filter_by(id=1).update({'name':'ccc'})
session.query(User).filter(User.id > 0).update({User.name: User.name + "099"}, synchronize_session=False) # 如果要把它转成字符串相加,synchronize_session=False必须有
session.query(User).filter(User.id > 0).update({"age": User.age + 1}, synchronize_session="evaluate")  # 如果要把它转成数字相加, synchronize_session="evaluate"必须有

#4.简单查
res=session.query(User).all()
res=session.query(User).first()
res=session.query(User).filter(User.id>=1).all()
 

  高级操作:

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import User,Person,Hobby
from sqlalchemy.sql import text
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session=Session()


# 1 查询名字为lqz的所有user对象
ret = session.query(User).filter_by(name='ccc099').all()

# 2 表达式,and条件连接
ret = session.query(User).filter(User.id > 1, User.name == 'egon').all()

# 3查找id在1和10之间,并且name=egon的对象
ret = session.query(User).filter(User.id.between(1, 10), User.name == 'egon').all()

# 4in条件(class_,因为这是关键字,不能直接用)
ret = session.query(User).filter(User.id.in_([1,3,4])).all()

# 5取反 ~
ret = session.query(User).filter(~User.id.in_([1,3,4])).all()

#6二次筛选(相当于sql子查询)
ret =
session.query(User).filter(User.id.in_(session.query(User.id).filter_by(name='egon'))).all()
# 指定具体字段的子查询
ret = session.query(User.id,User.name).filter(User.id.in_(session.query(User.id).filter_by(name='egon'))).all()

################
from sqlalchemy import and_, or_
#or_包裹的都是or条件,and_包裹的都是and条件
#查询id>3并且name=egon的人
ret = session.query(User).filter(and_(User.id > 3, User.name == 'egon')).all()

# 查询id大于2或者name=ccc099的数据
ret = session.query(User).filter(or_(User.id > 2, User.name == 'ccc099')).all()
ret = session.query(User).filter(
    or_(
        User.id < 2,
        and_(User.name == 'egon', User.id > 3),
        User.extra != ""
        )).all()
print(ret)

 
# 通配符,以e开头,不以e开头
ret = session.query(User).filter(User.name.like('e%')).all()
ret = session.query(User).filter(~User.name.like('e%')).all()


# 限制,用于分页,区间 limit
# 前闭后开区间,1能取到,3取不到
ret = session.query(User)[1:3]


# 排序,根据name降序排列(从大到小)
ret = session.query(User).order_by(User.name.desc()).all()
ret = session.query(User).order_by(User.name.asc()).all()
#第一个条件降序排序后,再按第二个条件升序排
ret = session.query(User).order_by(User.id.asc(),User.name.desc()).all()
ret = session.query(User).order_by(User.name.desc(),User.id.asc()).all()


# 分组
from sqlalchemy.sql import func
ret = session.query(User).group_by(User.name).all()
#分组之后取最大id,id之和,最小id
# sql 分组之后,要查询的字段只能有分组字段和聚合函数
ret = session.query(
    func.max(User.id),
    func.sum(User.id),
    func.min(User.id),
    User.name).group_by(User.name).all()

for obj in ret:
    print(obj[0],'----',obj[1],'-----',obj[2],'-----',obj[3])
print(ret)

#haviing筛选,分组之后再筛选
ret = session.query(
    func.max(User.id),
    func.sum(User.id),     
   func.min(User.id)).group_by(User.name).having(func.min(User.id)
>2).all()

  多表操作:一对多

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import User,Person,Hobby,Boy,Girl,Boy2Girl
from sqlalchemy.sql import text
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/aaa", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session=Session()


###  1 一对多插入数据
obj=Hobby(caption='足球')
session.add(obj)
p=Person(name='张三',hobby_id=2)
session.add(p)

### 2 方式二(默认情况传对象有问题),需要有relationship字段
#Person表中要加 hobby = relationship('Hobby', backref='pers')
p=Person(name='李四',hobby=Hobby(caption='美女'))
# 等同于
p=Person(name='李四2')
p.hobby=Hobby(caption='美女2')
session.add(p)

###3 方式三,通过反向操作
hb = Hobby(caption='王五')
hb.pers = [Person(name='王六'), Person(name='王七')]
session.add(hb)


###4 查询(查询:基于连表的查询,基于对象的跨表查询)
#4.1 基于对象的跨表查询(子查询,两次查询)
# 正查
p=session.query(Person).filter_by(name='张三').first()
print(p)
print(p.hobby.caption)
# 反查
h=session.query(Hobby).filter_by(caption='王五').first()
print(h.pers)

#4.2 基于连表的跨表查(查一次)
# 默认根据外键连表
# isouter=True 左外连,表示Person left join Hobby,没有右连接,只需要改变表名即可
# 不写 inner join
person_list=session.query(Person,Hobby).join(Hobby,isouter=True).all()
print(person_list)
for row in person_list:
    print(row[0].name,row[1].caption)

ret = session.query(Person, Hobby).filter(Person.hobby_id == Hobby.id)
print(ret)

#join表,默认是inner join
ret = session.query(Person).join(Hobby)
ret = session.query(Hobby).join(Person,isouter=True)
print(ret)


# 指定连表字段(从来没用过)
ret = session.query(Person).join(Hobby,Person.nid==Hobby.id, isouter=True)
ret =
session.query(Person).join(Hobby,Person.hobby_id==Hobby.id, isouter=True).all()
print(ret)


# 组合。UNION 操作符用于合并两个或多个 SELECT 语句的结果集
# union和union all的区别:union会去重,而union all不会去重
q1 = session.query(User.name).filter(User.id > 2)  
q2 = session.query(User.name).filter(User.id < 8) 


q1 = session.query(User.id,User.name).filter(User.id > 2)  
q2 = session.query(User.id,User.name).filter(User.id < 8) 

ret = q1.union_all(q2).all()
ret1 = q1.union(q2).all()
print(ret)
print(ret1)

q1 = session.query(User.name).filter(User.id > 2)
q2 = session.query(Hobby.caption).filter(Hobby.nid < 2)
ret = q1.union_all(q2).all()

  多表操作:多对多

session.add_all([
    Boy(hostname='男明星1'),
    Boy(hostname='男明星2'),
    Girl(name='女明星1'),
    Girl(name='女明星2'),
])
session.add_all([
    Boy2Girl(girl_id=1, boy_id=1),
    Boy2Girl(girl_id=2, boy_id=1)
])


##### 要有girls = relationship('Girl', secondary='boy2girl', backref='boys')
girl = Girl(name='女明星3')
girl.boys = [Boy(hostname='男明星3'),Boy(hostname='男明星4')]
session.add(girl)

boy=Boy(hostname='男明星5')
boy.girls=[Girl(name='女明星4'),Girl(name='女明星5')]
session.add(boy)
session.commit()


# 基于对象的跨表查
girl=session.query(Girl).filter_by(id=3).first()
print(girl.boys)

#基于连表的跨表查询
# 查询男明星4约过的所有妹子
'''
原生sql
select girl.name from girl,boy,Boy2Girl where boy.id=Boy2Girl.boy_id and girl.id=Boy2Girl.girl_id where boy.name='男明星4'

'''
ret=session.query(Girl.name).filter(Boy.id==Boy2Girl.boy_id,Girl.id==Boy2Girl.girl_id,Boy.hostname=='男明星4').all()

'''
原生sql
select girl.name from girl inner join Boy2Girl on girl.id=Boy2Girl.girl_id inner join boy on boy.id=Boy2Girl.boy_id where boy.hostname='男明星4'

'''
ret=session.query(Girl.name).join(Boy2Girl).join(Boy).filter(Boy.hostname=='男明星4').all()
ret=session.query(Girl.name).join(Boy2Girl).join(Boy).filter_by(hostname='男明星4').all()
print(ret)


### 执行原生sql(用的最多的)
#django中orm执行原生sql是另外的方法

cursor = session.execute('insert into users(name) values(:value)',params={"value":'xxx'})
print(cursor.lastrowid)

session.commit()
session.close()

 

四、将上面的集成到flask-SQLAlchemy

  1 Flask-SQLAlchemy
  2 flask-migrate
      -python3 manage.py db init 初始化:只执行一次
      -python3 manage.py db migrate 等同于 makemigartions
      -python3 manage.py db upgrade 等同于migrate
   
  3 Flask-SQLAlchemy如何使用
      1 from flask_sqlalchemy import SQLAlchemy
      2 db = SQLAlchemy()
      3 db.init_app(app)
      4 以后在视图函数中使用
          -db.session 就是咱们讲的session
        
  4 flask-migrate的使用(表创建,字段修改)
      1 from flask_migrate import Migrate,MigrateCommand
      2 Migrate(app,db)
      3 manager.add_command('db', MigrateCommand)


  5 直接使用
      -python3 manage.py db init 初始化:只执行一次,创建migrations文件夹
      -python3 manage.py db migrate 等同于 makemigartions
      -python3 manage.py db upgrade 等同于migrate

  6具体使用:

 

  flask-sqlalchemy

 

# 安装
pip install flask-sqlalchemy

# 所有的导入都找下面的db
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

 

  flask-migrate

安装:
pip install flask-migrate

命令:manager.add_command('db1', MigrateCommand)

# 当项目第一次执行迁移的时候,只需要初始化一次
1、python3 manage.py db1 init 

2、python3 manage.py db1 migrate # 等同于django的makemigrations

3、python3 manage.py db1 upgrade # 等同于django的migrate

  account.py

from flask import Blueprint
from .. import db
from .. import models

account = Blueprint('account', __name__)


@account.route('/login')
def login():
    # db.session.add(models.Users(username='wmt', email='123@qq.com'))
    # #db.session.query(models.Users).all()
    # db.session.commit()
    # 添加示例
    """
    db.session.add(models.Users(username='lqz', pwd='123', gender=1))
    db.session.commit()

    obj = db.session.query(models.Users).filter(models.Users.id == 1).first()
    print(obj)

    PS: db.session和db.create_session
    """
    # db.session.add(models.Users(username='ali1', email='ali1@xx.com'))
    # db.session.commit()
    # db.session.close()
        # db.session.add(models.Users(username='ali2', email='ali2@xx.com'))
    # db.session.commit()
    # db.session.close()
# db.session.add(models.Users(username='alx1',email='alx1@live.com')) # db.session.commit() # db.session.close() user_list = db.session.query(models.Users).all() for item in user_list: print(item.username,"is",item.email) return 'login'

  __init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

# from .models import *
from .views import account

def create_app():
    app = Flask(__name__)
    app.config.from_object('settings.BaseConfig')

    # 将db注册到app中
    db.init_app(app)

    # 注册蓝图
    app.register_blueprint(account.account)


    return app

  models.py

from . import db

class Users(db.Model):
    """
    用户表
    """
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

  manage.py

from .sansa import create_app
from flask_script import Manager
# flask_migrate管理数据迁移的 from flask_migrate import Migrate,MigrateCommand from .sansa import db app = create_app() manager=Manager(app) # 将当前app,与db注册到Migrate Migrate(app,db) # 添加管理数据的命令 manager.add_command('db1', MigrateCommand) if __name__ == '__main__': manager.run()

  settings.py

class BaseConfig(object):
    # SESSION_TYPE = 'redis'           # session类型为redis
    # SESSION_KEY_PREFIX = 'session:'  # 保存到session中的值的前缀
    # SESSION_PERMANENT = True         # 如果设置为False,则关闭浏览器session就失效。
    # SESSION_USE_SIGNER = False       # 是否对发送到浏览器上 session:cookie值进行加密

    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:@127.0.0.1:3306/day96?charset=utf8"
    SQLALCHEMY_POOL_SIZE = 5
    SQLALCHEMY_POOL_TIMEOUT = 30
    SQLALCHEMY_POOL_RECYCLE = -1

    # 追踪对象的修改并且发送信号
    SQLALCHEMY_TRACK_MODIFICATIONS = False


class ProductionConfig(BaseConfig):
    return('开发配置')


class DevelopmentConfig(BaseConfig):
    return('上线配置')


class TestingConfig(BaseConfig):
    return('测试配置')

 

posted @ 2022-03-23 20:51  新入世界的小白  阅读(56)  评论(0编辑  收藏  举报