一对多表操作

一对多表操作

一、创建建表

# 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:root@127.0.0.1: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:root@127.0.0.1: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:root@127.0.0.1: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:root@127.0.0.1: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:root@127.0.0.1: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:root@127.0.0.1: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:root@127.0.0.1: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中类名实现左右连接查询,第二种方式就是通过正反向查询实现连表查询
在当下的阶段,必将由程序员来主导,甚至比以往更甚。
原文地址:https://www.cnblogs.com/randysun/p/15518319.html