1. 程式人生 > 其它 >一對多表操作

一對多表操作

一對多表操作

一、建立建表

# model.py
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
from sqlalchemy.orm import relationship

Base = declarative_base()

# make_declarative_base
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而不是類名,uselist=False
    hobby_id = Column(Integer, ForeignKey("hobby.id"))

    # 跟資料庫無關,不會新增欄位,只用於快速連結串列操作
    # 類名,backref用於反向查詢
    hobby = relationship('Hobby', backref='perss')

    def __repr__(self):
        return self.name


def init_db():
    """
    根據類建立資料庫表
    :return:
    """
    engine = create_engine(
        "mysql+pymysql://root:[email protected]:3306/db_flask?charset=utf8",
        max_overflow=0,  # 超過連線池大小外最多建立的連線
        pool_size=5,  # 連線池大小
        pool_timeout=30,  # 池中沒有執行緒最多等待的時間,否則報錯
        pool_recycle=-1  # 多久之後對執行緒池中的執行緒進行一次連線的回收(重置)
    )

    Base.metadata.create_all(engine)


def drop_db():
    """
    根據類刪除資料庫表
    :return:
    """
    engine = create_engine(
        "mysql+pymysql://root:[email protected]:3306/db_flask?charset=utf8",
        max_overflow=0,  # 超過連線池大小外最多建立的連線
        pool_size=5,  # 連線池大小
        pool_timeout=30,  # 池中沒有執行緒最多等待的時間,否則報錯
        pool_recycle=-1  # 多久之後對執行緒池中的執行緒進行一次連線的回收(重置)
    )

    Base.metadata.drop_all(engine)


if __name__ == '__main__':
    # 建立表
    init_db()

    # 刪除表
    # drop_db()

二、新增資料

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from model import Users, Hobby, Person

engine = create_engine("mysql+pymysql://root:[email protected]:3306/db_flask", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 1. 新增資料

# 方式一
session.add_all([
    Hobby(caption='乒乓球'),
    Hobby(caption='羽毛球'),
    Person(name='張三', hobby_id=1),
    Person(name='李四', hobby_id=2),
])

# 方式二
# Hobby 愛好會自動插入一個愛好,即使存在也會插入資料
# 正向查詢欄位hoppy新增
person = Person(name='張三', hobby=Hobby(caption='跑腿'))
session.add(person)

# 方式三

hb = Hobby(caption='羽毛球')  
# 通過反向查詢欄位,新增資料perss 是關聯欄位
hb.perss = [Person(name='文飛'), Person(name='波波')]

session.add(hb)
session.commit()

三、正、反向查詢

3.1 正向查詢

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from model import Users, Hobby, Person

engine = create_engine("mysql+pymysql://root:[email protected]:3306/db_flask", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 2. relationship正向查詢
person = session.query(Person).first()
print(person.name)

# 正向查詢, 當前類中有外來鍵成為正向查詢,正向查詢只會有一個與其對應的愛好(單條記錄)
print(person.hobby)
print(person.hobby.caption)

3.1 反向查詢

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from model import Users, Hobby, Person

engine = create_engine("mysql+pymysql://root:[email protected]:3306/db_flask", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 3. relationship 反向查詢
hobby = session.query(Hobby).filter(Hobby.id == 1).first()
print(hobby.caption)
# 物件列表,反向查詢的結果是一個類表物件(因為是一對多的關係,在person可能有多個愛好被被關聯),所以要使用循壞一個個遍歷
print(hobby.perss)
print(hobby.perss[0].nid, hobby.perss[0].name)

3.3 斷關聯連表查詢

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from model import Users, Hobby, Person

engine = create_engine("mysql+pymysql://root:[email protected]:3306/db_flask", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()

# 3. 斷關聯
# 斷關聯:是兩張表中沒有設定外來鍵關聯,所以只能通過邏輯進行關聯,使用.join( Person.hobby_id == Hobby.id)
# Person.hobby_id == Hobby.id 斷關聯這個條件必須要寫,通過join實現表之間的關聯
# isouter=True 左關聯,False為 inner join 等值關聯
# query中的表和join表來調換表的查詢關係
ret = session.query(Person).join(Hobby, Person.hobby_id == Hobby.id, isouter=False)
print(ret)

# 設定了外來鍵關聯,就不需要設定 Person.hobby_id == Hobby.id 條件
person_list = session.query(Hobby).join(Person, isouter=True)
print(person_list)

person_list = session.query(Person, Hobby).join(Hobby).all()
print(person_list)
for row in person_list:
    # print(row.name,row.caption)
    # 第一個為person物件, 第二位hobby物件
    print(row[0].name, row[1].caption)

3.4 通過relationship連表查詢

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from model import Users, Hobby, Person

engine = create_engine("mysql+pymysql://root:[email protected]:3306/db_flask", max_overflow=0, pool_size=5)
Session = sessionmaker(bind=engine)
session = Session()
# 通過relationship
person_list = session.query(Person).all()

print(person_list)

for row in person_list:
    print(row.name, row.hobby.caption)
    
# obj = session.query(Hobby).filter(Hobby.id == 1).first()
# persons = obj.perss
# print(persons)
    

三、總結

  • 新增資料:可以通過add_all新增資料並設定關聯外來鍵欄位值,還可以通過正反向查詢向新增表之間的關係,會自定設定關聯的外來鍵值
  • 正向查詢:當前表中有外來鍵欄位稱為正向查詢,正向查詢單條資料對一個愛好資料
  • 反向查詢:當前表中沒有外來鍵欄位稱為反向查詢,反向查詢單條資料可會被多個人喜歡,所以查出來為列表物件,是一個集合
  • 連表查詢:可以通過兩種方式進行查詢,一種是通過表之間的關鍵關係通過 .join方法實現連表查詢,需要注意的是表之間是否有級聯關係,也就是是否設定了外來鍵,如果沒有則需要在.join中通過邏輯條件實現連表查詢,通過調至query和.join中類名實現左右連線查詢,第二種方式就是通過正反向查詢實現連表查詢
在當下的階段,必將由程式設計師來主導,甚至比以往更甚。