flask08_days

拆尼斯、帕丁顿發表於2024-03-10

一對多關係

關係

import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index

Base = declarative_base()  # Base 當成 models.Model


### 單表
class User(Base):
    __tablename__ = 'users'  # 表名
    # 寫欄位
    id = Column(Integer, primary_key=True, autoincrement=True)  # id 主鍵
    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)
    extra = Column(Text)

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name


# 一對多 :一個興趣被多個人喜歡  一個人只喜歡一個興趣
class Hobby(Base):
    __tablename__ = 'hobby'
    id = Column(Integer, primary_key=True)
    caption = Column(String(50), default='籃球')

    def __str__(self):
        return self.caption

    def __repr__(self):
        return self.caption


class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    name = Column(String(32), index=True, nullable=True)
    # hobby指的是tablename而不是類名,uselist=False
    # 外來鍵關聯--》強外來鍵--》物理外來鍵
    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 sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Hobby, Person, User

engine = create_engine(
    "mysql+pymysql://root:1234@127.0.0.1:3306/sqlalchemy02",
    max_overflow=0,  # 超過連線池大小外最多建立的連線
    pool_size=5,  # 連線池大小
    pool_timeout=30,  # 池中沒有執行緒最多等待的時間,否則報錯
    pool_recycle=-1  # 多久之後對執行緒池中的執行緒進行一次連線的回收(重置)
)

Session = sessionmaker(bind=engine)
session = Session()

# 1  增加 Hobby
# hobby = Hobby(caption='足球')
# hobby1 = Hobby()
# session.add_all([hobby, hobby1])
# session.commit()

# 2 增加Person
# p1 = Person(name='彭于晏', hobby_id=1)
# p2 = Person(name='劉亦菲', hobby_id=2)
# session.add_all([p1, p2])
# session.commit()

# 3 簡便方式增加person---》增加Person,直接新增Hobby
# hobby1 = Hobby(caption='乒乓球')
# p1 = Person(name='彭于晏', hobby=hobby1) # 前提是必須有relationship
# session.add(p1)
# session.commit()

# # 4 基於物件的跨表查詢---正向
# per=session.query(Person).filter_by(name='彭于晏').first()
# print(per)
# # 正向
# print(per.hobby.caption)

# 5 基於物件的跨表查詢---正向
hobby=session.query(Hobby).filter_by(caption='籃球').first()
print(hobby)
# 反向--->拿到多條
print(hobby.pers)
print(hobby.pers[0].name)  # 列表套物件

多對多關係

關係

import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index

Base = declarative_base()  # Base 當成 models.Model


### 單表
class User(Base):
    __tablename__ = 'users'  # 表名
    # 寫欄位
    id = Column(Integer, primary_key=True, autoincrement=True)  # id 主鍵
    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)
    extra = Column(Text)

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name


# 一對多 :一個興趣被多個人喜歡  一個人只喜歡一個興趣
class Hobby(Base):
    __tablename__ = 'hobby'
    id = Column(Integer, primary_key=True)
    caption = Column(String(50), default='籃球')

    def __str__(self):
        return self.caption

    def __repr__(self):
        return self.caption


class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    name = Column(String(32), index=True, nullable=True)
    # hobby指的是tablename而不是類名,uselist=False
    # 外來鍵關聯--》強外來鍵--》物理外來鍵
    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


# 多對多
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'))
    # boy = relationship('Boy', backref='boy')


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)
    name = Column(String(64), unique=True, nullable=False)

    # 與生成表結構無關,僅用於查詢方便,放在哪個單表中都可以--等同於manytomany
    girls = relationship('Girl', secondary='boy2girl', backref='boys')


if __name__ == '__main__':
    # 3.1 建立引擎
    engine = create_engine(
        "mysql+pymysql://root:1234@127.0.0.1:3306/sqlalchemy02",
        max_overflow=0,  # 超過連線池大小外最多建立的連線
        pool_size=5,  # 連線池大小
        pool_timeout=30,  # 池中沒有執行緒最多等待的時間,否則報錯
        pool_recycle=-1  # 多久之後對執行緒池中的執行緒進行一次連線的回收(重置)
    )
    ## 3.2 把表模型同步到資料庫中
    Base.metadata.create_all(engine)

    # 3.3 刪除表
    # Base.metadata.drop_all(engine)

操作

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Hobby, Person, User, Boy, Girl, Boy2Girl

engine = create_engine(
    "mysql+pymysql://root:1234@127.0.0.1:3306/sqlalchemy02",
    max_overflow=0,  # 超過連線池大小外最多建立的連線
    pool_size=5,  # 連線池大小
    pool_timeout=30,  # 池中沒有執行緒最多等待的時間,否則報錯
    pool_recycle=-1  # 多久之後對執行緒池中的執行緒進行一次連線的回收(重置)
)

Session = sessionmaker(bind=engine)
session = Session()

# 1  增加 Boy
# boy = Boy(name='王小剛')
# boy2 = Boy(name='王小明')
# boy3 = Boy(name='王小勇')
# session.add_all([boy,boy2,boy3])
# session.commit()
# 2 增加Girl
# girl = Girl(name='張小華')
# girl2 = Girl(name='劉小紅')
# girl3 = Girl(name='李小麗')
# session.add_all([girl3, girl2, girl])
# session.commit()
# 3 增加Boy2Girl
# obj1=Boy2Girl(boy_id=1,girl_id=1)
# obj2=Boy2Girl(boy_id=1,girl_id=2)
# obj3=Boy2Girl(boy_id=1,girl_id=3)
# session.add_all([obj2, obj3, obj1])
# session.commit()

# ------

# 3 簡便方式增加

# obj2=Girl(name='張亦菲')
# obj3=Girl(name='李娜扎')
# obj1=Boy(name='張小勇',girls=[obj2,obj3])
#
# session.add(obj1)
# session.commit()

# # 4 基於物件的跨表查詢---正向
# boy=session.query(Boy).filter_by(name='張小勇').first()
# print(boy.girls[0].name)


# 5 基於物件的跨表查詢---反向
girl=session.query(Girl).filter_by(name='張亦菲').first()
print(girl.boys)

scoped執行緒安全

# session 物件,整合到flask中去,要把session物件做成全域性(大家公用),還是每個檢視函式獨有一個(每次都要例項化得到這個session物件)


# 每個檢視函式獨有一個---》每次都要例項化---》sqlalchemy提供了一種方式,讓咱們使用全域性的一個session,但是每個檢視函式中使用的都是不同的  request,session都是這種實現機制


# sqlalchemy提供了一種,在不同執行緒中,雖然使用全域性 session,實際上每個執行緒自己獨有一個session
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from models import Users
from threading import local
engine = create_engine("mysql+pymysql://root:lqz123?@127.0.0.1:3306/sqlalchemy01", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)

"""
# 執行緒安全,基於本地執行緒實現每個執行緒用同一個session
# 特殊的:scoped_session中有原來方法的Session中的一下方法:

public_methods = (
    '__contains__', '__iter__', 'add', 'add_all', 'begin', 'begin_nested',
    'close', 'commit', 'connection', 'delete', 'execute', 'expire',
    'expire_all', 'expunge', 'expunge_all', 'flush', 'get_bind',
    'is_modified', 'bulk_save_objects', 'bulk_insert_mappings',
    'bulk_update_mappings',
    'merge', 'query', 'refresh', 'rollback',
    'scalar'
)
"""
# session=Session() # 不是執行緒安全---》多執行緒併發情況下---》用的是同一個,就會出現混亂
#scoped_session類並沒有繼承Session,但是卻又它的所有方法

# 以後在多執行緒,協程情況下,使用這個session,就沒有併發安全的問題
# 原理是什麼? 內部使用了threading包下local物件,   local.session  在不同執行緒下執行這個取值或賦值,使用的都是當前執行緒自己的

# 執行緒1   local.a=100  後續的操作中--->取local.a--->永遠是當時這條執行緒中放進去的a ,也就是100
# 執行緒2   local.a=999   --->取local.a--->永遠是當時這條執行緒中放進去的a ,也就是999

#local物件如何實現的執行緒安全呢? 內部維護了一個字典,字典的key是執行緒id號,value值是
# l=local()  #  {}
# # 執行緒1 
# l.session=執行緒1的session  # {執行緒1的id號:{session:新session}}
# 
# # 執行緒2 
# l.session# {執行緒1的id號:{session:新session},執行緒2的id號:{session:執行緒2的session}}



# 本質就是,不同執行緒,使用自己執行緒的那個session
# scoped_session 不是Session類的物件,但是他有 Session類物件的所有方法----》透過裝飾器,裝進去的
session = scoped_session(Session)
# ############# 執行ORM操作 #############
obj1 = Users(name="lqz4",email='3533@qq.com')
session.add(obj1)

# 提交事務
session.commit()
# 關閉session
session.close()

基本增刪查改

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from models import User, Person, Hobby, Boy, Girl, Boy2Girl
from sqlalchemy.sql import text

engine = create_engine("mysql+pymysql://root:1234@127.0.0.1:3306/sqlalchemy02", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = scoped_session(Session)

# 1 新增, add   add_all

# 2 刪除
# 2.1 session.query(Users).filter_by(id=1).delete()
# 2.1 session.delete(物件)
# user = session.query(User).filter_by(id=1).first()
# session.delete(user)
# session.commit()

#  修改
#  1 方式一:
# session.query(Boy).filter_by(id=1).update({'name':'lqz'})
# session.commit()

# # 2 方式二  類名.屬性名,作為要修改的key
# session.query(Boy).filter_by(id=4).update({Boy.name:'lqz1'})
# session.commit()


# # id為4的人的名字後+  _nb   類似於django的 F 查詢
# session.query(User).filter_by(id=2).update({'name':User.name+'_nb'},synchronize_session=False) # 字串拼接
# session.query(User).filter_by(id=2).update({'id':User.id+6}, synchronize_session="evaluate") # 數字之間加
# session.commit()


# # 3 方式三:
# 物件.name='xxx'
#session.add(物件)
# boy=session.query(Boy).filter_by(id=1).first()
# boy.name='xxzzyy'
# session.add(boy) # 有id就是修改,沒有就是新增
# session.commit()



### 4 查詢---》基本查詢
# 4.1 filter_by  寫條件
# res=session.query(User).filter_by(name='lqz_nb',id=8).first()
# res=session.query(User).filter_by(name='lqz').all()  # 放在列表中 不是queryset物件



# 4.2 filter  寫表示式
# res=session.query(User).filter(User.name=='lqz_nb').first()
# res=session.query(User).filter(User.id>=3).all()
# res=session.query(User).filter(User.name!='lqz').all()


# 4.3 只查表中某幾個欄位,並重新命名
# select name as xx,age from user;
# res=session.query(User.name.label('xx'), User.email)

# select name,email from user;
# res=session.query(User.name, User.email).all()
# res=session.query(User)


# 4.4 條件可以使用text自己拼湊
# select * from user where id< 224 and name=lqz order by id
# res = session.query(User).filter(text("id<:value and name=:name")).params(value=224, name='lqz_nb').order_by(User.id).all()
# print(res)



## 4.5 直接原生sql
# SELECT * FROM users where name=lqz
# res = session.query(User).from_statement(text("SELECT * FROM users where name=:name")).params(name='lqz_nb').all()
res = session.query(User).from_statement(text("SELECT * FROM users where name=:name")).params(name='張三')
print(res)