sqlalchemy

sqlalchemy

https://docs.sqlalchemy.org/en/20/orm/quickstart.html

1 快速使用

安装 2.0.30版本

pip3 insatll sqlalchemy 

架构

Engine,框架的引擎
Connection Pooling ,数据库连接池
Dialect,选择连接数据库的DB API种类 
SQL Exprression Language,SQL表达式语言

链接不同数据库

postgresql

engine = create_engine("postgresql://scott:tiger@localhost/mydatabase")
# psycopg2
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/mydatabase")
# pg8000
engine = create_engine("postgresql+pg8000://scott:tiger@localhost/mydatabase")

Mysql

# default
engine = create_engine("mysql://scott:tiger@localhost/foo")
# mysqlclient (a maintained fork of MySQL-Python)
engine = create_engine("mysql+mysqldb://scott:tiger@localhost/foo")
# PyMySQL
engine = create_engine("mysql+pymysql://scott:tiger@localhost/foo")

oracle

engine = create_engine("oracle://scott:tiger@127.0.0.1:1521/sidname")
engine = create_engine("oracle+cx_oracle://scott:tiger@tnsname")

Microsoft SQL Server

# pyodbc
engine = create_engine("mssql+pyodbc://scott:tiger@mydsn")
# pymssql
engine = create_engine("mssql+pymssql://scott:tiger@hostname:port/dbname")

sqlite

# Unix/Mac - 4 initial slashes in total
engine = create_engine("sqlite:////absolute/path/to/foo.db")
# Windows
engine = create_engine("sqlite:///C:\\path\\to\\foo.db")
# Windows alternative using raw string
engine = create_engine(r"sqlite:///C:\path\to\foo.db")

2 原生操作

import threading
from sqlalchemy import create_engine
engine = create_engine(
    "mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
)

def task():
    conn = engine.raw_connection()
    cursor = conn.cursor()
    cursor.execute(
        "select * from user"
    )
    result = cursor.fetchall()
    print(result)
    cursor.close()
    conn.close()

for i in range(20):
    t = threading.Thread(target=task)
    t.start()

3 sqlalchemy操作表

1 建表删表

from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
import datetime
# 创建基类,以后所有类,都必须继承基类

# 老版本创建基类(不建议)
# from sqlalchemy.ext.declarative import declarative_base
# Base = declarative_base()

# 新版本创建基类
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    pass


# 写个类,继承
# 写字段:传统方式,类型方式
class User(Base):
    __tablename__='user'
    id=Column(Integer,primary_key=True,autoincrement=True)
    name = Column(String(32), index=True, nullable=False)  # name列varchar32,索引,不可为空
    email = Column(String(32), unique=True)  # email 列,varchar32,唯一
    # datetime.datetime.now不能加括号,加了括号,以后永远是当前时间
    ctime = Column(DateTime, default=datetime.datetime.now)
    extra = Column(Text, nullable=True)


if __name__ == '__main__':
    from sqlalchemy import create_engine

    engine = create_engine(
        "mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8",
        max_overflow=0, 
        pool_size=5, 
        pool_timeout=30,  
        pool_recycle=-1 
    )
    # 创建表(不能创建库,只能新增或删除表,不能增加删除字段)
    Base.metadata.create_all(engine)

    # 删除表
    # Base.metadata.drop_all(engine)

2 数据增删查改

from models import User
# 创建engine
from sqlalchemy import create_engine
engine = create_engine(
    "mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8",
    max_overflow=0, 
    pool_size=5, 
    pool_timeout=30,
    pool_recycle=-1
)

# 创建 session对象---老方式
# from sqlalchemy.orm import sessionmaker
# Session = sessionmaker(bind=engine)
# session=Session()
# 创建 session对象---新方式(推荐)
from sqlalchemy.orm import Session
session=Session(engine)

新增

user=User(name='qc',email='35@qq.com')
session.add(user)
session.commit()  #提交
session.close()

新增多条

user1=User(name='tom',email='344@qq.com')
user2=User(name='jom',email='335@qq.com')
session.add_all([user1,user2])
session.commit()
session.close()

res=session.query(User).filter_by(name='qc').all()
# res=session.query(User).filter_by(id=1).all()
print(res)
print(res[0])

删除

res=session.query(User).filter_by(name='lqz').delete()
print(res)
session.commit()

修改一

session.query(User).filter_by(id=2).update({'name':'ooo'})
session.commit()

修改二

user=session.query(User).filter_by(id=2).first()
user.name='uuii'
session.add(user) #[id字段在不在] 如果对象不存在,就是新增,如果对象存在,就是修改
session.commit()

4 一对多关系

models.py

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship

from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
    pass

class Hobby(Base):
    __tablename__ = 'hobby'
    id = Column(Integer, primary_key=True)
    caption = Column(String(50), default='篮球')
    def __str__(self):
        return self.caption


class Person(Base):
    __tablename__ = 'person'
    nid = Column(Integer, primary_key=True)
    name = Column(String(32), index=True, nullable=True)
    # hobby指的是tablename而不是类名
    hobby_id = Column(Integer, ForeignKey("hobby.id")) 

    # 跟数据库无关,不会新增字段,只用于快速链表操作
    # 类名,backref用于反向查询
    hobby = relationship('Hobby', backref='pers')
    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name

使用

from models import Person,Hobby
from sqlalchemy import create_engine
engine = create_engine(
    "mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8",
    max_overflow=0, 
    pool_size=5,
    pool_timeout=30, 
    pool_recycle=-1
)


from sqlalchemy.orm import Session
session=Session(engine)

(笨办法)

# 1 先增加一个hobby
hobby=Hobby()
session.add(hobby)
session.commit()
# 2 增加Person---》必须要有hobby_id
person=Person(name='qc',hobby_id=1)
session.add(person)
session.commit()

((简便方法)

person = Person(name='qc', hobby=Hobby(caption='乒乓球'))
session.add(person)
session.commit()
hobby=session.query(Hobby).filter_by(id=1).first()
person = Person(name='qc1', hobby=hobby)
session.add(person)
session.commit()

基于对象的跨表查询--->正向

# hobby = relationship('Hobby', backref='pers')
person=session.query(Person).filter_by(nid=2).first()
print(person)
print(person.hobby_id)
print(person.hobby)

基于对象的跨表查询--->反向

# hobby = relationship('Hobby', backref='pers')
hobby = session.query(Hobby).filter_by(id=1).first()
print(hobby.caption)
print(hobby.pers)

5 多对多关系

models.py

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import DeclarativeBase


class Base(DeclarativeBase):
    pass


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 __repr__(self):
        return self.name


class Boy(Base):
    __tablename__ = 'boy'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(64), unique=True, nullable=False)

    girls = relationship('Girl', secondary='boy2girl', backref='boys')

    def __repr__(self):
        return self.name

使用

from models import Boy, Girl, Boy2Girl
from sqlalchemy import create_engine

engine = create_engine(
    "mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8",
    max_overflow=0,
    pool_size=5,
    pool_timeout=30,
    pool_recycle=-1
)

from sqlalchemy.orm import Session

session = Session(engine)

普通增加

boy = Boy(name='cat')
boy1 = Boy(name='adr')
girl = Girl(name='red')
girl1 = Girl(name='pink')
session.add_all([boy,girl,boy1,girl1])
session.commit()
# 往中间表增加记录
res=Boy2Girl(boy_id=1,girl_id=1)
session.add_all([res])
session.commit()

快捷添加

girls = session.query(Girl).filter(Girl.id >= 2).all()
print(girls)
boy = session.query(Boy).filter(Boy.id == 1).first()
boy.girls = girls
session.add(boy)
session.commit()
# 新用户建立关联
girls = session.query(Girl).filter(Girl.id >= 2).all()
boy = Boy(name='fff',girls=girls)
session.add(boy)
session.commit()

基于对象的跨表查询--->正向

#girls = relationship('Girl', secondary='boy2girl', backref='boys')
boy = session.query(Boy).filter(Boy.id == 1).first()
print(boy.name)
print(boy.girls)

基于对象的跨表查询--->反向

#girls = relationship('Girl', secondary='boy2girl', backref='boys')
girl = session.query(Girl).filter(Girl.id == 2).all()[0]
print(girl.name)
print(girl.boys)

6 常用查询

1 filter_by

res=session.query(User).filter_by(name='aaa').all() # 返回列表
res=session.query(User).filter_by(name='aaa').first() # 返回单条

2 filter[where]

res=session.query(User).filter(User.id>1).all()
res=session.query(User).where(User.id>1).all()

3 between

# select * from user where id between 1 and 3
res=session.query(User).where(User.id.between(1,3)).all()

4 in

# select * from user where id in (1,3,4)
res = session.query(User).filter(User.id.in_([1, 3, 4])).all()

5 ~ (非,not in)

# select * from user where id not in (1,3,4)
res = session.query(User).filter(~User.id.in_([1, 3, 4])).all()

6 二次筛选

# select * from user where user.id in (select id from user where name='xxx')
res = session.query(User).where(User.id.in_(session.query(Person.nid).filter_by(name='xxx'))).all()

7 and,or 条件

from sqlalchemy import and_, or_

# select * from user where id=3 and name='aaa'
res = session.query(User).filter(and_(User.id ==3, User.name == 'aaa')).all()

# select * from user where id>1 or name='qdd'
res = session.query(User).filter(or_(User.id > 1, User.name == 'qdd')).all()

8 通配符,以e开头,不以e开头

# select * from user where name like 'a%'
res = session.query(User).filter(User.name.like('a%')).all()
# select * from user where name not like 'a%'
res = session.query(User).filter(~User.name.like('a%')).all()
# select * from user where name like 'a_'  _ 表示只有一位
res = session.query(User).filter(User.name.like('a_')).all()

9 限制,用于分页,区间

# select * from user limit 3
res = session.query(User)[0:3]
print(res)

10 排序 desc asc

# select * from user order by name  升序 默认
res = session.query(User).order_by(User.name).all()

# select * from user order by name desc  降序
res = session.query(User).order_by(User.name.desc()).all()

11 分组

# select name,count(*) from user group by name
res = session.query(func.count(User.name), User.name).group_by(User.name).all()

12 having筛选

# select name,count(*) from user group by name having count(*)>1
res = session.query(func.count(User.name), User.name).group_by(User.name).having(func.count(User.id) > 1).all()

13 连表(默认用forinkey关联)

# select * from person,hobby where person.hobby_id=hobby.id;
res=session.query(Person,Hobby).where(Person.hobby_id==Hobby.id).all()

14 join表

默认是inner join

# select * from person inner join hobby on person.hobby_id=hobby.id;
res = session.query(Person).join(Hobby).all()

left join

isouter=True 外连,表示 left join

# select * from person left join hobby on person.hobby_id=hobby.id;
res=session.query(Person).join(Hobby,isouter=True)

right join

没有右连接,反过来即可

# select * from person right join hobby on person.hobby_id=hobby.id;
ret = session.query(Hobby).join(Person, isouter=True)

自定义连表

# 自己指定on条件(连表条件),第二个参数,支持on多个条件,用and_,同上因为我们可以没有强外键关联
    ret = session.query(Person).join(Hobby, Person.nid == Hobby.id, isouter=True)

7 scoped线程安全

全局就用一个session对象,它在不同线程中---》都是这个线程自己的

from models import User
import threading
# 第一步:创建engine
from sqlalchemy import create_engine
engine = create_engine(
    "mysql+pymysql://root:1234@127.0.0.1:3306/sqlalchemy001?charset=utf8",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_recycle=-1  # 多久之后对线程池中的线程进行一次连接的回收(重置)
)

# 第二步:创建 线程安全的 session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
Session = sessionmaker(bind=engine)
session=scoped_session(Session)

# 第三步:正常使用-->再flask中,使用全局的session即可,实现:不同线程使用线程自己的session对象
def task(se,i):
    session=se()
    session.add(User(name='xxx',email=f'{i}@qq.com'))
    session.commit()
    print('=========',session)

if __name__ == '__main__':
    l=[]
    for i in range(10):
        t=threading.Thread(target=task,args=[session,i])
        t.start()
        l.append(t)
    for i in l:
        i.join()

8 flask-sqlalchemy使用

1 集成到项目中(自己集成)

models.py

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__='user'
    id=Column(Integer,primary_key=True,autoincrement=True)
    name = Column(String(32), index=True, nullable=False) 
    email = Column(String(32), unique=True)

    
    
    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name

db.py

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = scoped_session(Session)

app.py

from flask import Flask, jsonify
from .models import User
from .db import session

app = Flask(__name__)
app.debug = True

@app.get('/')
def index():
    res = session.query(User).filter(User.id >= 1).all()
    result = []
    for user in res:
        user_data = {
            'id': user.id,
            'name': user.name,
            'age': user.email
        }
        result.append(user_data)
    return jsonify({'code': 100, 'result': result})

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

2 使用flask-sqlalchemy集成到flask中

安装

pip install Flask-sqlalchemy

使用步骤

1 导入 from flask_sqlalchemy import SQLAlchemy
2 实例化得到对象 db = SQLAlchemy(app)
3 models.py 中继承Model
4 视图函数中使用session
	全局的db.session  # 线程安全的
5 配置文件中加入


"""
├── 项目
    ├── src/      
     	├── __init__.py	
        ├── models.py
        ├── settings.py
		├── views.py
    └── static/    
    ├── templates/
    └── app.py   
"""

代码

__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__, template_folder='../templates', static_folder='../static')
app.config.from_pyfile('./settings.py')
db = SQLAlchemy(app)

from .views import bp_user

app.register_blueprint(bp_user)

models.py

from . import db


class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32), index=True, nullable=False)
    email = db.Column(db.String(32), unique=True)

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name

settings.py

DEBUG = True
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123456@127.0.0.1:3306/sqlalchemy01?charset=utf8"
SQLALCHEMY_POOL_SIZE = 5
SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = -1
# 追踪对象的修改并且发送信号
SQLALCHEMY_TRACK_MODIFICATIONS = False

views.py

from flask import Blueprint, jsonify
from .models import User
from . import db

bp_user = Blueprint('user', __name__)


@bp_user.get('/')
def index():
    res = db.session.query(User).where(User.id > 1).all()
    l = []
    for i in res:
        l.append({'name': i.name, 'email': i.email})
    return jsonify({'code': 100, 'msg': '成功', 'results': l})

app.py

from src import app

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

9 flask-migrate使用

安装

pip3 install Flask-Migrate --upgrade

使用

__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__, template_folder='../templates', static_folder='../static')
app.config.from_pyfile('./settings.py')
db = SQLAlchemy(app)
migrate = Migrate(app, db)

from .views import bp_user

app.register_blueprint(bp_user)

初始化

flask db init

生成迁移文件

 flask db migrate

迁移记录生效------同步到真正的数据库

flask db upgrade

视图里要调用表模型

10 django操作原生sql


	# 方式一:
    from django.db import connection
    cur=connection.cursor() 
    cur.execute('select distinct id, book_name from test_book')
    print(cur.fetchall())
    cur.close()
    
    # 方式二:
    # 原生sql,方式一,跟对象做映射:
	book_list=Book.objects.raw('select id,name,price,publish from app01_book where id =2')
    # print(book_list) # RawQuerySet
    # for book in book_list:
    #     print(book.name)

# obj_list = User.objects.raw('select id,name,price,publish from app01_book where id =2')
# print(obj_list)  # RawQuerySet
# for obj in obj_list:
#     print(obj.name)
#     print(obj.price)
posted @ 2024-06-24 08:59  蓝幻ﹺ  阅读(15)  评论(0编辑  收藏  举报