国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Flask】SQLAlchemy

這篇具有很好參考價值的文章主要介紹了【Flask】SQLAlchemy。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

SQLAlchemy是什么

為什么使用orm

優(yōu)點

  • 有語法提示, 省去自己拼寫SQL,保證SQL語法的正確性
  • orm提供方言功能(dialect, 可以轉(zhuǎn)換為多種數(shù)據(jù)庫的語法), 減少學(xué)習(xí)成本
  • 防止sql注入攻擊
  • 搭配數(shù)據(jù)遷移, 更新數(shù)據(jù)庫方便
  • 面向?qū)ο? 可讀性強, 開發(fā)效率高

缺點

  • 需要語法轉(zhuǎn)換, 效率比原生sql低
  • 復(fù)雜的查詢往往語法比較復(fù)雜 (可以使用原生sql替換)

定義

SQLAlchemy是一個基于Python實現(xiàn)的ORM框架。該框架建立在 DB API之上,使用關(guān)系對象映射進(jìn)行數(shù)據(jù)庫操作,簡言之便是:將類和對象轉(zhuǎn)換成SQL,然后使用數(shù)據(jù)API執(zhí)行SQL并獲取執(zhí)行結(jié)果。

安裝

pip3 install sqlalchemy

組成部分

  • Engine,框架的引擎
  • Connection Pooling ,數(shù)據(jù)庫連接池
  • Dialect,選擇連接數(shù)據(jù)庫的DB API種類
  • Schema/Types,架構(gòu)和類型
  • SQL Exprression Language,SQL表達(dá)式語言

SQLAlchemy本身無法操作數(shù)據(jù)庫,其必須以來pymsql等第三方插件

MySQL-Python
    mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
    
pymysql
    mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
    
MySQL-Connector
    mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
    
cx_Oracle
    oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
    
更多:http://docs.sqlalchemy.org/en/latest/dialects/index.html

SQLAlchemy的使用

原生sql

from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine
from urllib import parse
import threading

user = "root"
password = "xxx@000"
pwd = parse.quote_plus(password)   # 解決密碼中含@符導(dǎo)致報錯
host = "127.0.0.1:"
# 第一步: 創(chuàng)建engine
engine = create_engine(
    f"mysql+pymysql://{user}:{pwd}@{host}3306/test1?charset=utf8",
    max_overflow=0,  # 超過連接池大小外最多創(chuàng)建的連接
    pool_size=5,  # 連接池大小
    pool_timeout=30,  # 池中沒有線程最多等待的時間,否則報錯
    pool_recycle=-1  # 多久之后對線程池中的線程進(jìn)行一次連接的回收(重置)
)


# 第二步:使用
def task():
    conn = engine.raw_connection()  # 從連接池中取一個連接
    cursor = conn.cursor()
    sql = "select * from signer"
    cursor.execute(sql)
    print(cursor.fetchall())


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

使用orm映射數(shù)據(jù)表

import datetime
from sqlalchemy.ext.declarative import declarative_base
from model import engine  # 用的簡單使用里面的engine
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index

Base = declarative_base()   # 基類

# 表模型
class Users(Base):
    __tablename__ = 'users'  # 數(shù)據(jù)庫表名稱, 必須寫
    
    id = Column(Integer, primary_key=True)  # id 主鍵
    name = Column(String(32), index=True, nullable=False)  # name列,索引,不可為空
    email = Column(String(32), unique=True)
    # datetime.datetime.now不能加括號,加了括號,以后永遠(yuǎn)是當(dāng)前時間
    ctime = Column(DateTime, default=datetime.datetime.now)
    extra = Column(Text, nullable=True)

    __table_args__ = (   # 可選
        UniqueConstraint('id', 'name', name='uix_id_name'),  # 聯(lián)合唯一
        Index('ix_id_name', 'name', 'email'),  # 索引
    )

def init_db():
    """
    根據(jù)類創(chuàng)建繼承base類的表
    :return:
    """

    Base.metadata.create_all(engine)


def drop_db():
    """
    根據(jù)類刪除繼承base類的表
    :return:
    """

    Base.metadata.drop_all(engine)


if __name__ == '__main__':
		# sqlalchemy 只支持 創(chuàng)建和刪除表,不支持修改表(django orm支持)。sqlalchemy 需要借助第三方實現(xiàn)
    init_db()  # 創(chuàng)建表
    # drop_db()   # 刪除表

外鍵關(guān)系

一對多(ForeignKey)

class Hobby(Base):
    __tablename__ = 'hobby'
    id = Column(Integer, primary_key=True)
    caption = Column(String(50), default='籃球')


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"))
    
    # 跟數(shù)據(jù)庫無關(guān),不會新增字段,只用于快速鏈表操作
    # 類名,backref用于反向查詢  參數(shù) uselist=False , 設(shè)置就變成了一對一,其他和一對多一樣
    hobby=relationship('Hobby',backref='pers')
    # hobby=relationship('Hobby',backref='pers', uselist=False)  # 一對一關(guān)系

多對多

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)


class Boy(Base):
    __tablename__ = 'boy'

    id = Column(Integer, primary_key=True, autoincrement=True)
    hostname = Column(String(64), unique=True, nullable=False)
    
    # 與生成表結(jié)構(gòu)無關(guān),僅用于查詢方便,放在哪個單表中都可以
    servers = relationship('Girl', secondary='boy2girl', backref='boys')
    
'''
girl_id = Column(Integer, ForeignKey("hobby.id", ondelete='SET NULL'))  # 一般用SET NULL
外鍵約束
    1. RESTRICT:若子表中有父表對應(yīng)的關(guān)聯(lián)數(shù)據(jù),刪除父表對應(yīng)數(shù)據(jù),會阻止刪除。默認(rèn)項
    2. NO ACTION:在MySQL中,同RESTRICT。
    3. CASCADE:級聯(lián)刪除。
    4. SET NULL:父表對應(yīng)數(shù)據(jù)被刪除,子表對應(yīng)數(shù)據(jù)項會設(shè)置為NULL。
'''

擴(kuò)充:在 django 中,外鍵管理有個參數(shù) db_contraint=False 用來在邏輯上關(guān)聯(lián)表,但實體不建立約束。同樣在SQLAlchemy 中也可以通過配值 relationship 參數(shù)來實現(xiàn)同樣的效果

class Boy2Girl(Base):
    __tablename__ = 'boy2girl'
    id = Column(Integer, primary_key=True, autoincrement=True)
    girl_id = Column(Integer)  # 不用ForeignKey
    boy_id = Column(Integer)
    
    gitl = db.relationship(
        "Girl",
        # uselist=False,  # 一對一設(shè)置
        backref=backref("to_course", uselist=False),  # backref用于反向查詢 uselist 作用同上
        lazy="subquery",    # 懶加載 用來指定sqlalchemy 什么時候加載數(shù)據(jù)
        primaryjoin="Girl.id==Boy2Girl.girl_id",  # 指定對應(yīng)關(guān)系
        foreign_keys="Boy2Girl.girl_id"  # 指定表的外鍵字段
    )
'''
lazy 可選值
    select:就是訪問到屬性的時候,就會全部加載該屬性的數(shù)據(jù)  默認(rèn)值
    joined:對關(guān)聯(lián)的兩個表使用聯(lián)接
    subquery:與joined類似,但使用子子查詢
    dynamic:不加載記錄,但提供加載記錄的查詢,也就是生成query對象
'''

使用orm操作記錄

簡單表操作

from sqlalchemy.orm import sessionmaker

from model import engine
from db_model import Users

# 定義一個 session, 以后操作數(shù)據(jù)都用 session 來執(zhí)行
Session = sessionmaker(bind=engine)
session = Session()
# 創(chuàng)建User對象
usr = Users(name="yxh", email="152@11.com", extra="xxx")
# 通過 user對象 添加到session中 
session.add(usr)
# 提交,才會刷新到數(shù)據(jù)庫中,不提交不會執(zhí)行
session.commit()

基于scoped_session實現(xiàn)線程安全

session 如果是一個全局對象。那么在多線程的情況下,并發(fā)使用同一個變量 session 是不安全的,解決方案如下:

  • 將session定義在局部,每一個view函數(shù)都定義一個session。 代碼冗余,不推薦

  • 基于scoped_session 實現(xiàn)線程安全。原理同 request對象,g對象一致。也是基于local,給每一個線程創(chuàng)造一個session

from sqlalchemy.orm import sessionmaker, scoped_session
from model import engine
from db_model import Users

# 定義一個 session
Session = sessionmaker(bind=engine)
# session = Session()
session = scoped_session(Session)  # 后續(xù)使用這個session就是線程安全的
# 創(chuàng)建User對象
usr = Users(name="yxh", email="152@11.com", extra="xxx")
# 通過 user對象 添加到session中
session.add(usr)
# 提交,才會刷新到數(shù)據(jù)庫中,不提交不會執(zhí)行
session.commit()

CRUD

創(chuàng)建(Create)、讀?。≧ead)、更新(Update)和刪除(Delete)

基礎(chǔ)操作

from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.sql import text
from model import engine
from db_model import Users

# 定義一個 session
Session = sessionmaker(bind=engine)
# session = Session()
session = scoped_session(Session)  # 后續(xù)使用這個session就是線程安全的

# 1  增加操作
obj1 = Users(name="yxh003")
session.add(obj1)
# 增加多個,不同對象
session.add_all([
    Users(name="yxh009"),
    Users(name="yxh008"),
])
session.commit()

# 2 刪除操作---》查出來再刪---》
session.query(Users).filter(Users.id > 2).delete()
session.commit()

# 3 修改操作--》查出來改  傳字典
session.query(Users).filter(Users.id > 0).update({"name": "yxh"})
# 類似于django的F查詢
# 字符串加
session.query(Users).filter(Users.id > 0).update({Users.name: Users.name + "099"}, synchronize_session=False)
# 數(shù)字加
session.query(Users).filter(Users.id > 0).update({"age": Users.age + 1}, synchronize_session="evaluate")
session.commit()

# 4 查詢操作----》
r1 = session.query(Users).all()  # 查詢所有
# 只取age列,把name重命名為xx
# select name as xx,age from user;
r2 = session.query(Users.name.label('xx'), Users.email).all()

# filter傳的是表達(dá)式,filter_by傳的是參數(shù)
r3 = session.query(Users).filter(Users.name == "yxh").all()
r3 = session.query(Users).filter(Users.id >= 1).all()
r4 = session.query(Users).filter_by(name='yxh').all()
r5 = session.query(Users).filter_by(name='yxh').first()
# :value 和:name 相當(dāng)于占位符,用params傳參數(shù)
r6 = session.query(Users).filter(text("id<:value and name=:name")).params(value=224, name='yxh').order_by(
    Users.id).all()
# 自定義查詢sql
r7 = session.query(Users).from_statement(text("SELECT * FROM users where name=:name")).params(name='yxh').all()

# 執(zhí)行原生sql
# 查詢
cursor = session.execute("select * from users")
result = cursor.fetchall()
# 添加
cursor = session.execute('insert into users(name) values(:value)', params={"value": 'yxh'})
session.commit()
print(cursor.lastrowid)

進(jìn)階操作

from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.sql import text, func
from sqlalchemy import and_, or_
from model import engine
from db_model import Users, Person, Favor

# 定義一個 session
Session = sessionmaker(bind=engine)
# session = Session()
session = scoped_session(Session)  # 后續(xù)使用這個session就是線程安全的

#  條件
# select * form user where name =lqz
ret = session.query(Users).filter_by(name='lqz').all()

# 表達(dá)式,and條件連接
# select * from user where id >1 and name = lqz
ret = session.query(Users).filter(Users.id > 1, Users.name == 'lqz').all()

# select * from user where id between 1,3  and name = lqz
ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'lqz').all()

# # 注意下劃線
#  select * from user where id in (1,3,4)
ret = session.query(Users).filter(Users.id.in_([1, 3, 4])).all()
# # ~非,除。。外

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

# # 二次篩選
ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='lqz'))).all()

# # or_包裹的都是or條件,and_包裹的都是and條件
ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all()
ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all()
ret = session.query(Users).filter(
    or_(
        Users.id < 2,
        and_(Users.name == 'eric', Users.id > 3),
        Users.extra != ""
    )).all()

# 通配符,以e開頭,不以e開頭
ret = session.query(Users).filter(Users.name.like('e%')).all()
ret = session.query(Users).filter(~Users.name.like('e%')).all()

# # 限制,用于分頁,區(qū)間
ret = session.query(Users)[1:2]

# # 排序,根據(jù)name降序排列(從大到?。?ret = session.query(Users).order_by(Users.id.desc()).all()
# # 第一個條件重復(fù)后,再按第二個條件升序排
ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all()

# 分組
# select * from user group by user.extra;
ret = session.query(Users).group_by(Users.extra).all()
# # 分組之后取最大id,id之和,最小id
# select max(id),sum(id),min(id) from user group by name ;
ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).group_by(Users.name).all()

# haviing篩選
#  select max(id),sum(id),min(id) from user group by name  having min(id)>2;
ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) > 2).all()

# select max(id),sum(id),min(id) from user where id >=1 group by name  having min(id)>2;
ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).filter(Users.id >= 1).group_by(Users.name).having(func.min(Users.id) > 2).all()

# 連表(默認(rèn)用orm中forinkey關(guān)聯(lián))

# select * from user,favor where user.id=favor.id
ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all()

# join表,默認(rèn)是inner join
# select * from Person inner join favor on person.favor=favor.id;
ret = session.query(Person).join(Favor).all()
# isouter=True 外連,表示Person left join Favor,沒有右連接,反過來即可
ret = session.query(Person).join(Favor, isouter=True).all()
ret = session.query(Favor).join(Person, isouter=True).all()

# 打印原生sql
aa = session.query(Person).join(Favor, isouter=True)
# print(aa)

# 自己指定on條件(連表條件),第二個參數(shù),支持on多個條件,用and_,同上
# select * from person left join favor on person.id=favor.id;
ret = session.query(Person).join(Favor, Person.id == Favor.id, isouter=True).all()

# 組合 UNION 操作符用于合并兩個或多個 SELECT 語句的結(jié)果集 多用于分表后 上下連表 
# union和union all  union 去重, union all 不去重
q1 = session.query(Users.name).filter(Users.id > 2)
q2 = session.query(Favor.caption).filter(Favor.nid < 2)
ret = q1.union(q2).all()

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

Flask集成sqlalchemy

'''
flask_migrate  中使用了flask_sqlalchemy 下載時,會自動幫你下載flask_sqlalchemy
flask_migrate  3.0之前和之后使用方法有區(qū)別。這里以2.x 做演示
'''
# flask_migrate使用步驟
from flask_sqlalchemy import SQLAlchemy
# Flask_SQLAlchemy給你包裝了基類,和session,以后拿到db
db = SQLAlchemy()  # 全局SQLAlchemy,就是線程安全的,內(nèi)部就是上述那么實現(xiàn)的
app = Flask(__name__)
# SQLAlchemy 連接數(shù)據(jù)庫配置是在 config 配置字典中獲取的,所以需要我們將配置添加進(jìn)去
app.config.from_object('DevelopmentConfig')
'''
基本寫這些就夠了
"SQLALCHEMY_DATABASE_URI"  
"SQLALCHEMY_POOL_SIZE"
"SQLALCHEMY_POOL_TIME"
"SQLALCHEMY_POOL_RECYCLE"
"SQLALCHEMY_TRACK_MODIFICATIONS"
"SQLALCHEMY_ENGINE_OPTIONS"
'''
# 將db注冊到app中,加載配置文件,flask-session,用一個類包裹一下app
db.init_app(app)
# 將需要使用orm操作的表通過繼承db.Model實現(xiàn)類


# 下面三句會創(chuàng)建出兩個命令:runserver db 命令(flask_migrate)
manager=Manager(app)
Migrate(app, db)
manager.add_command('db', MigrateCommand) # 添加一個db命令

使用命令:
    1. python xxx.py db init  # 初始化,剛開始干,生成一個migrate文件夾(遷移文件夾)
    2. python xxx.py db migrate   # 生成遷移版本,保存到遷移文件夾,同django  makemigartions
    3. python xxx.py db upgrade   # 執(zhí)行遷移,同django  migrate
配置選項 示例值 說明
SQLALCHEMY_DATABASE_URI 'sqlite:///database.db' 數(shù)據(jù)庫連接字符串,指定要連接的數(shù)據(jù)庫類型、用戶名、密碼、主機(jī)和數(shù)據(jù)庫名稱等信息
SQLALCHEMY_TRACK_MODIFICATIONS False 是否跟蹤對象修改。默認(rèn)為True。建議在生產(chǎn)環(huán)境中將其設(shè)置為False,以提高性能
SQLALCHEMY_ECHO True 是否將生成的SQL語句輸出到控制臺上。主要用于調(diào)試和開發(fā),默認(rèn)為False
SQLALCHEMY_POOL_SIZE 10 數(shù)據(jù)庫連接池的大小,默認(rèn)為5
SQLALCHEMY_POOL_TIMEOUT 20 等待數(shù)據(jù)庫連接的超時時間(秒),默認(rèn)為10
SQLALCHEMY_POOL_RECYCLE 3600 連接在重新使用之前的最大時間(秒)。默認(rèn)為-1,表示禁用連接回收
SQLALCHEMY_NATIVE_UNICODE False 控制是否使用數(shù)據(jù)庫驅(qū)動程序的本機(jī)Unicode支持。默認(rèn)為False
SQLALCHEMY_COMMIT_ON_TEARDOWN True 是否在請求結(jié)束時自動提交事務(wù)。默認(rèn)為False。在某些情況下,可以將其設(shè)置為True,以自動提交更改到數(shù)據(jù)庫
SQLALCHEMY_BINDS {'users': 'sqlite:///users.db'} 定義多個數(shù)據(jù)庫連接的綁定。
SQLALCHEMY_ENGINE_OPTIONS {'pool_size':10, 'connect_timeout':20, 'encoding':'utf8mb4'} 具體參數(shù)和效果取決于所使用的數(shù)據(jù)庫驅(qū)動程序和 SQLAlchemy 版本

構(gòu)建模型類

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 相關(guān)配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True

# 創(chuàng)建組件對象
db = SQLAlchemy(app)


# 構(gòu)建模型類  類->表  類屬性->字段  實例對象->記錄
# 模型類必須繼承 db.Model, 其中 db 指對應(yīng)的組件對象
class User(db.Model):
    __tablename__ = 't_user'  # 設(shè)置表名, 表名默認(rèn)為類名小寫
    id = db.Column(db.Integer, primary_key=True)  # 設(shè)置主鍵, 默認(rèn)自增
    name = db.Column('username', db.String(20), unique=True)  # 設(shè)置字段名 和 唯一約束
    age = db.Column(db.Integer, default=10, index=True)  # 設(shè)置默認(rèn)值約束 和 索引


if __name__ == '__main__':
    # 刪除所有繼承自db.Model的表
    db.drop_all()
    # 創(chuàng)建所有繼承自db.Model的表
    db.create_all()
    app.run(debug=True)

常用的字段類型

字段類型 示例 說明
Integer age = db.Column(db.Integer) 整數(shù)類型
String name = db.Column(db.String(100)) 字符串類型
Text content = db.Column(db.Text) 長文本類型
Float height = db.Column(db.Float) 浮點數(shù)類型
Boolean is_active = db.Column(db.Boolean, default=False) 布爾類型
DateTime created_at = db.Column(db.DateTime) 日期和時間類型
Date birth_date = db.Column(db.Date) 日期類型
Time meeting_time = db.Column(db.Time) 時間類型
JSON data = db.Column(db.JSON) 存儲 JSON 數(shù)據(jù)的字段類型
PickleType data = db.Column(db.PickleType) 存儲 Python 對象的字段類型
Enum status = db.Column(db.Enum('active', 'inactive', name='status_enum')) 枚舉類型,用于限制字段取值范圍
ForeignKey user_id = db.Column(db.Integer, db.ForeignKey('user.id')) 外鍵類型,用于與其他模型類建立關(guān)聯(lián)
relationship user = db.relationship('User', backref='posts') 定義模型之間的關(guān)系
backref - 在關(guān)系另一側(cè)創(chuàng)建反向引用
primary_key=True id = db.Column(db.Integer, primary_key=True) 將字段設(shè)置為主鍵
unique=True email = db.Column(db.String(100), unique=True) 將字段設(shè)置為唯一值
nullable=False name = db.Column(db.String(100), nullable=False) 設(shè)置字段為非空
default is_active = db.Column(db.Boolean, default=False) 設(shè)置字段的默認(rèn)值
index=True username = db.Column(db.String(100), index=True) 為字段創(chuàng)建索引
server_default created_at = db.Column(db.DateTime, server_default=db.func.now()) 在數(shù)據(jù)庫服務(wù)器上設(shè)置字段的默認(rèn)值

常用的字段選項

字段選項 示例 說明
primary_key=True id = db.Column(db.Integer, primary_key=True) 將字段設(shè)置為主鍵
unique=True email = db.Column(db.String(100), unique=True) 將字段設(shè)置為唯一值
nullable=False name = db.Column(db.String(100), nullable=False) 設(shè)置字段為非空
default is_active = db.Column(db.Boolean, default=False) 設(shè)置字段的默認(rèn)值
index=True username = db.Column(db.String(100), index=True) 為字段創(chuàng)建索引
autoincrement=True id = db.Column(db.Integer, primary_key=True, autoincrement=True) 設(shè)置字段自增
server_default created_at = db.Column(db.DateTime, server_default=db.func.now()) 在數(shù)據(jù)庫服務(wù)器上設(shè)置字段的默認(rèn)值
onupdate updated_at = db.Column(db.DateTime, onupdate=db.func.now()) 在字段更新時設(shè)置新的值
foreign_key user_id = db.Column(db.Integer, db.ForeignKey('user.id')) 定義字段與其他表的外鍵關(guān)系
backref posts = db.relationship('Post', backref='user') 在關(guān)系的另一側(cè)創(chuàng)建反向引用
lazy posts = db.relationship('Post', lazy='dynamic') 控制字段加載的時機(jī)
uselist users = db.relationship('User', backref='role', uselist=False) 控制關(guān)系字段是否作為列表返回
cascade posts = db.relationship('Post', cascade='delete') 控制級聯(lián)操作的行為
passive_deletes posts = db.relationship('Post', passive_deletes=True) 控制刪除時的級聯(lián)行為
passive_updates posts = db.relationship('Post', passive_updates=True) 控制更新時的級聯(lián)行為
ondelete post_id = db.Column(db.Integer, db.ForeignKey('post.id', ondelete='CASCADE')) 在刪除關(guān)聯(lián)記錄時的處理方式
primaryjoin posts = db.relationship('Post', primaryjoin='and_(User.id == Post.user_id, User.is_active == True)') 指定關(guān)系字段之間的條件表達(dá)式
secondary users = db.relationship('User', secondary='user_role', backref='roles') 定義多對多關(guān)系中的中間表
secondaryjoin users = db.relationship('User', secondary='user_role', secondaryjoin='and_(User.id == user_role.user_id, user_role.is_active == True)') 指定多對多關(guān)系中中間表與主表之間的條件表達(dá)式

# 1.創(chuàng)建模型對象
user1 = User(name='zs', age=20)
# user1.name = 'zs'
# user1.age = 20

# 2.將模型對象添加到會話中 
db.session.add(user1)
# 添加多條記錄
# db.session.add_all([user1, user2, user3])

# 3.提交會話 (會提交事務(wù))
# sqlalchemy會自動創(chuàng)建隱式事務(wù)
# 事務(wù)失敗會自動回滾
db.session.commit()

# 查詢所有用戶數(shù)據(jù)
User.query.all() 返回列表, 元素為模型對象

# 查詢有多少個用戶
User.query.count()

# 查詢第1個用戶
User.query.first()  返回模型對象/None

# 查詢id為4的用戶[3種方式]
# 方式1: 根據(jù)id查詢  返回模型對象/None
User.query.get(4)  
# 方式2: 等值過濾器 關(guān)鍵字實參設(shè)置字段值  返回BaseQuery對象
# BaseQuery對象可以續(xù)接其他過濾器/執(zhí)行器  如 all/count/first等
User.query.filter_by(id=4).all()  
# 方式3: 復(fù)雜過濾器  參數(shù)為比較運算/函數(shù)引用等  返回BaseQuery對象
User.query.filter(User.id == 4).first()

# 查詢名字結(jié)尾字符為g的所有用戶[開始 / 包含]
User.query.filter(User.name.endswith("g")).all()
User.query.filter(User.name.startswith("w")).all()
User.query.filter(User.name.contains("n")).all()
User.query.filter(User.name.like("w%n%g")).all()  # 模糊查詢

# 查詢名字和郵箱都以li開頭的所有用戶[2種方式]
User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all()
from sqlalchemy import and_
User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all()

# 查詢age是25 或者 `email`以`itheima.com`結(jié)尾的所有用戶
from sqlalchemy import or_
User.query.filter(or_(User.age==25, User.email.endswith("itheima.com"))).all()

# 查詢名字不等于wang的所有用戶[2種方式]
from sqlalchemy import not_
User.query.filter(not_(User.name == 'wang')).all()
User.query.filter(User.name != 'wang').all()

# 查詢id為[1, 3, 5, 7, 9]的用戶
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()

# 所有用戶先按年齡從小到大, 再按id從大到小排序, 取前5個
User.query.order_by(User.age, User.id.desc()).limit(5).all()

# 查詢年齡從小到大第2-5位的數(shù)據(jù)   2 3 4 5
User.query.order_by(User.age).offset(1).limit(4).all()

# 分頁查詢, 每頁3個, 查詢第2頁的數(shù)據(jù)  paginate(頁碼, 每頁條數(shù))
pn = User.query.paginate(2, 3)
pn.pages 總頁數(shù)  pn.page 當(dāng)前頁碼 pn.items 當(dāng)前頁的數(shù)據(jù)  pn.total 總條數(shù)


# 查詢每個年齡的人數(shù)    select age, count(name) from t_user group by age  分組聚合
from sqlalchemy import func
data = db.session.query(User.age, func.count(User.id).label("count")).group_by(User.age).all()
for item in data:
    # print(item[0], item[1])
    print(item.age, item.count)  # 建議通過label()方法給字段起別名, 以屬性方式獲取數(shù)據(jù)

# 只查詢所有人的姓名和郵箱  優(yōu)化查詢   User.query.all()  # 相當(dāng)于select *
from sqlalchemy.orm import load_only
data = User.query.options(load_only(User.name, User.email)).all()  # flask-sqlalchem的語法
for item in data:
    print(item.name, item.email)

data = db.session.query(User.name, User.email).all()  # sqlalchemy本體的語法
for item in data:
    print(item.name, item.email)

先查詢, 再更新

對應(yīng)SQL中的 先select, 再commit()

  • 缺點

    • 查詢和更新分兩條語句, 效率低
    • 如果并發(fā)更新, 可能出現(xiàn)更新丟失問題(Lost Update)
  • 示例文章來源地址http://www.zghlxwxcb.cn/news/detail-548878.html

    # 1.執(zhí)行查詢語句, 獲取目標(biāo)模型對象
    goods = Goods.query.filter(Goods.name == '方便面').first()
    # 2.對模型對象的屬性進(jìn)行賦值 (更新數(shù)據(jù))
    goods.count = goods.count - 1
    # 3.提交會話
    db.session.commit()
    
基于過濾條件的更新 (推薦方案)

對應(yīng)SQL中的 update xx where xx = xx (也稱為 update子查詢 )

  • 優(yōu)點

    • 一條語句, 被網(wǎng)絡(luò)IO影響程度低, 執(zhí)行效率更高
    • 查詢和更新在一條語句中完成, 單條SQL具有原子性, 不會出現(xiàn)更新丟失問題
    • 會對滿足過濾條件的所有記錄進(jìn)行更新, 可以實現(xiàn)批量更新處理
  • 示例

    Goods.query.filter(Goods.name == '方便面').update({'count': Goods.count - 1})
    # 提交會話
    db.session.commit()
    

先查詢, 再刪除
# 方式1: 先查后刪除
goods = Goods.query.filter(Goods.name == '方便面').first()
# 刪除數(shù)據(jù)
db.session.delete(goods)
# 提交會話 增刪改都要提交會話
db.session.commit()
基于過濾條件的刪除 (推薦方案)
# 方式2: delete子查詢
Goods.query.filter(Goods.name == '方便面').delete()
# 提交會話
db.session.commit()

到了這里,關(guān)于【Flask】SQLAlchemy的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【Flask】from flask_sqlalchemy import SQLAlchemy報錯

    【Flask】from flask_sqlalchemy import SQLAlchemy報錯

    在使用 flask_sqlalchemy 之前,你需要確保已經(jīng)通過 pip 安裝了 Flask-SQLAlchemy??梢酝ㄟ^以下命令安裝它: ? ?pip install Flask-SQLAlchemy Python 是區(qū)分大小寫的,確保在導(dǎo)入和使用模塊時大小寫與實際安裝的庫名稱一致。確保你在代碼中使用的是 SQLAlchemy,而不是 SQLAlchem。 正確的導(dǎo)入

    2024年02月09日
    瀏覽(15)
  • 快速上手Flask(三) 在 Flask應(yīng)用中使用Flask-SQLAlchemy(flask SQLAlchemy模型對象如何json序列化輸出)

    常見情況下對于只有一個 Flask 應(yīng)用,所有您需要做的事情就是創(chuàng)建 Flask 應(yīng)用,選擇加載配置接著創(chuàng)建 SQLAlchemy 對象時候把 Flask 應(yīng)用傳遞給它作為參數(shù)。 官網(wǎng):https://www.sqlalchemy.org/ 參考本人 文章:python常用庫之?dāng)?shù)據(jù)庫orm框架之SQLAlchemy 官方文檔: 中文: http://www.pythondoc.co

    2024年01月25日
    瀏覽(31)
  • Flask數(shù)據(jù)庫操作-Flask-SQLAlchemy

    Flask數(shù)據(jù)庫操作-Flask-SQLAlchemy

    Flask中一般使用flask-sqlalchemy來操作數(shù)據(jù)庫。flask-sqlalchemy的使用介紹如下: 一、SQLAlchemy SQLALchemy 實際上是對數(shù)據(jù)庫的抽象,讓開發(fā)者不用直接和 SQL 語句打交道,而是通過 Python 對象來操作數(shù)據(jù)庫,在舍棄一些性能開銷的同時,換來的是開發(fā)效率的較大提升。 SQLAlchemy是一個關(guān)

    2024年02月22日
    瀏覽(27)
  • Python - flask后端開發(fā)筆記

    ? Flask入門 有一篇很全面的博客可以參考:Python Flask Web 框架入門 跨域問題處理 文件發(fā)送 ?

    2024年02月07日
    瀏覽(26)
  • 【Flask】SQLAlchemy

    為什么使用orm 優(yōu)點 有語法提示, 省去自己拼寫SQL,保證SQL語法的正確性 orm提供方言功能(dialect, 可以轉(zhuǎn)換為多種數(shù)據(jù)庫的語法), 減少學(xué)習(xí)成本 防止sql注入攻擊 搭配數(shù)據(jù)遷移, 更新數(shù)據(jù)庫方便 面向?qū)ο? 可讀性強, 開發(fā)效率高 缺點 需要語法轉(zhuǎn)換, 效率比原生sql低 復(fù)雜的查詢往

    2024年02月13日
    瀏覽(19)
  • Flask-SQLAlchemy

    Flask-SQLAlchemy

    認(rèn)識Flask-SQLAlchemy Flask-SQLAlchemy 是一個為 Flask 應(yīng)用增加 SQLAlchemy 支持的擴(kuò)展。它致力于簡化在 Flask 中 SQLAlchemy 的使用。 SQLAlchemy 是目前python中最強大的 ORM框架, 功能全面, 使用簡單。 ORM優(yōu)缺點 優(yōu)點 有語法提示, 省去自己拼寫SQL,保證SQL語法的正確性 orm提供方言功能(dialect, 可

    2024年02月12日
    瀏覽(23)
  • Flask-數(shù)據(jù)庫-SQLAlchemy

    Flask-數(shù)據(jù)庫-SQLAlchemy

    SQLAlchemy是flask的擴(kuò)展,是一個功能強大的OR映射器,支持多種數(shù)據(jù)庫后臺,可以將類的對象映射至數(shù)據(jù)庫表。 使用這個工具,可以創(chuàng)建數(shù)據(jù)庫,創(chuàng)建表,并為數(shù)據(jù)庫添加數(shù)據(jù),進(jìn)行查詢操作等。 參考:Flask SQLAlchemy - Flask 教程 | BootWiki.com ?app=Flask(__name__)? #創(chuàng)建Flask實例 ?app

    2023年04月09日
    瀏覽(24)
  • flask-sqlalchemy使用

    # sqlalchemy 集成到flask中 # 第三方: flask-sqlalchemy 封裝了用起來,更簡潔 安裝 使用

    2024年02月13日
    瀏覽(31)
  • flask中的操作數(shù)據(jù)庫的插件Flask-SQLAlchemy

    flask中的操作數(shù)據(jù)庫的插件Flask-SQLAlchemy

    Web 開發(fā)中,一個重要的組成部分便是數(shù)據(jù)庫了。Web 程序中最常用的莫過于關(guān)系型數(shù)據(jù)庫了,也稱 SQL 數(shù)據(jù)庫。另外,文檔數(shù)據(jù)庫(如 mongodb)、鍵值對數(shù)據(jù)庫(如 redis)近幾年也逐漸在 web 開發(fā)中流行起來,我們習(xí)慣把這兩種數(shù)據(jù)庫稱為 NoSQL 數(shù)據(jù)庫。 大多數(shù)的關(guān)系型數(shù)據(jù)庫引

    2024年02月09日
    瀏覽(33)
  • flask----內(nèi)置信號的使用/django的信號/ flask-script/sqlalchemy介紹和快速使用/sqlalchemy介紹和快速使用

    內(nèi)置信號的使用 有哪些內(nèi)置信號 自定義信號 # 1 第一步:定義一個自定義 信號 # 2 第二步:寫個函數(shù) # 3 第三步:函數(shù)跟自己定義信號綁定 # 4 第四步:觸發(fā)自定義信號---》我們做 ? 信號的作用(信號量--》Semaphore) 信號量 sqlalchemy的原生操作

    2024年02月14日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包