[Flask framework] - 26 ORM relationship

insert image description here

insert image description here


1. The foreign key association of the table

Using SQLAlchemyCreate foreign key is very simple. Add a field in the secondary table, and specify which field of the table is the foreign key of this field. The field of the foreign key in the secondary table must be consistent with the primary key field type of the main table.

This association only focuses on the foreign key association between data tables, and does not consider Pythonthe association relationship between objects.

# 部门和员工之间,是一种典型的一(主)对多(从)
class Department(Base):
    __tablename__ = 't_dept'
    dept_no = Column(Integer, primary_key=True)
    d_name = Column(String(255))  # 部门名字
    city = Column(String(50))


# 员工表
class Employee(Base):
    __tablename__ = 't_emp'
    emp_no = Column(Integer, primary_key=True)
    emp_name = Column(String(50))
    job = Column(String(50))
    hire_time = Column(DATE)  # 入职时间
    sal = Column(DECIMAL(10, 2))  # 薪资,连两位小数共十位
    dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='CASCADE'))

Delete option for foreign keys

  1. RESTRICT: If there is associated data corresponding to the parent table in the child table, deleting the data corresponding to the parent table will prevent the deletion. default item
  2. NO ACTION: in MySQL, the same RESTRICT.
  3. CASCADE: Cascade delete.
  4. SET NULL: The data corresponding to the parent table is deleted, and the data item corresponding to the child table is set to NULL.
from datetime import date
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('mysql+pymysql://root:root@localhost:3306/flask_db?charset=utf8mb4', echo=True)

Base = declarative_base(engine)


# 部门和员工之间,是一种典型的一(主)对多(从)
class Department(Base):
    __tablename__ = 't_dept'
    dept_no = Column(Integer, primary_key=True)
    d_name = Column(String(255))  # 部门名字
    city = Column(String(50))


# 员工表
class Employee(Base):
    __tablename__ = 't_emp'
    emp_no = Column(Integer, primary_key=True)
    emp_name = Column(String(50))  # 员工名字
    job = Column(String(50))
    hire_time = Column(DATE)  # 入职时间
    sal = Column(DECIMAL(10, 2))  # 薪资,连两位小数共十位
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='NO ACTION'))
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='CASCADE'))  # 级联删除
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='RESTRICT'))  #
    dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='SET NULL'))  #


Base.metadata.drop_all()
Base.metadata.create_all()


d1 = Department(d_name='人事部', city='昆明')
e1 = Employee(emp_name='张三', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=1)

# 创建session对象
session = sessionmaker(engine)()


def add():
    session.add(d1)
    session.add(e1)
    session.commit()


add()

# 删除
dept = session.query(Department).first()
session.delete(dept)
session.commit()

2. One-to-many/many-to-one in ORM

mysqlThe foreign key at the table level is not cool enough. You must get the foreign key of a table, and then use this foreign key to find it in another table, which is too troublesome.

SQLAlchemyOne is provided relationship. This class can define attributes, which can be accessed directly through attribute access when accessing the associated table in the future. In addition, the attribute name for reverse access can be specified backrefby . The relationship between departments and employees is a "one-to-many" relationship.

# -*- coding: utf-8 -*-

"""
@file: 数据库表的外键关联.py
@author: 北极的三哈
@time: 2022/12/26 14:56
@email:[email protected]
@software: PyCharm2022.3
"""
from datetime import date
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

engine = create_engine('mysql+pymysql://root:root@localhost:3306/flask_db?charset=utf8mb4', echo=True)

Base = declarative_base(engine)


# 部门和员工之间,是一种典型的一(主)对多(从)
class Dep(Base):
    __tablename__ = 't_dept'
    dept_no = Column(Integer, primary_key=True)
    d_name = Column(String(255))  # 部门名字
    city = Column(String(50))
    # 代表当前部门下所有员工的列表, 这种写法不是最优的, 最优的写法只要在其中一个对象中关联
    emp = relationship("Emp")  # 参数必须是另外一个相关联的类名

    def __str__(self):
        return 'DEP:<部门名字:{}, 城市:{}>'.format(self.d_name, self.city)


# 员工表
class Emp(Base):
    __tablename__ = 't_emp'
    emp_no = Column(Integer, primary_key=True)
    emp_name = Column(String(50))  # 员工名字
    job = Column(String(50))
    hire_time = Column(DATE)  # 入职时间
    sal = Column(DECIMAL(10, 2))  # 薪资,连两位小数共十位
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='NO ACTION'))
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='CASCADE'))  # 级联删除
    dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='RESTRICT'))  #
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='SET NULL'))  #
    dept = relationship("Dep")

    def __str__(self):
        return "EMP:<员工编号:{}, 员工姓名:{}>".format(self.emp_no, self.emp_name)


Base.metadata.drop_all()
Base.metadata.create_all()


d1 = Dep(d_name='人事部', city='上海')
d2 = Dep(d_name='销售部', city='上海')
e1 = Emp(emp_name='张三', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=1)
e2 = Emp(emp_name='李四', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=1)
e3 = Emp(emp_name='王二', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=2)
e4 = Emp(emp_name='麻子', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=2)

# 创建session对象
session = sessionmaker(engine)()


def add():
    session.add(d1)
    session.add(d2)
    session.add_all([e1, e2, e3, e4])
    session.commit()


add()

# 查询一个部门,关联到部门的员工
d = session.query(Dep).first()
for e in d.emp:
    print(e)

e = session.query(Emp).filter(Emp.emp_no == 4).first()
print(e)
print(e.dept)

insert image description here


3. One-to-one in ORM

In sqlalchemy, if you want to map two models into a one-to-one relationship, you should pass a parameter of uselist=False when specifying a reference in the parent model. It is to tell the parent model that when this slave model is referenced in the future, it is no longer a list, but an
object.

Method 1: Refer to the one-to-many association, plususelist

Add uselist=Falseit to an object without a foreign key, and the others are the same as the previous one-to-many association.

class Person(Base):
    __tablename__ = 't_person'
    # 在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。
    # 这些属性必须是sqlalchemy给我们提供好的数据类型
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255))
    age = Column(Integer)
    address = Column(String(255))
    country = Column(String(50))
    # 人对应的身份证
    idcard = relationship('IDcard', uselist=False)


# 员工表
class IDcard(Base):
    __tablename__ = 't_emp'
    card_number = Column(String(18), primary_key=True)
    p_id = Column(Integer, ForeignKey('t_person.id'))  # 外键
    # 该身份证对应的人
    person = relationship('Person')

Method 2: There is no need to maintain the association relationship in the master table (no need to add association attributes), just add association attributes to the slave table object, and add backref

class Person(Base):
    __tablename__ = 't_person'
    # 在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。
    # 这些属性必须是sqlalchemy给我们提供好的数据类型
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255))
    age = Column(Integer)
    address = Column(String(255))
    country = Column(String(50))
    # 人对应的身份证
    # idcard = relationship('IDcard', uselist=False)  # 不是一个列表

    def __str__(self):
        return "Person[id:{}, name:{}, age:{}]".format(self.id, self.name, self.age)


# 身份证号
class IDcard(Base):
    __tablename__ = 't_idcard'
    card_number = Column(String(18), primary_key=True)
    p_id = Column(Integer, ForeignKey('t_person.id'))  # 外键
    # 该身份证对应的人
    person = relationship('Person', backref=backref('idcard', uselist=False))

4. Many-to-many in ORM

  1. The many-to-many relationship needs to bind the relationship between them through an intermediate table.

  2. First define two models that need to do many-to-many

  3. Use to Tabledefine an intermediate table, the intermediate table is generally a foreign key field containing two models, and let them both be used as a "composite primary key".

  4. Choose a model randomly among the two models that need to do many-to-many, and define an relationshipattribute to bind the relationship between the three. When using it relationship, you need to pass in a secondary=intermediate table object name.

# 学生和课程之间多对多关系
# 1.定义中间表
temp_tab = Table(
    't_temp_tab',
    Base.metadata,
    # 3.定义中间表联合主键
    Column('s_id', Integer, ForeignKey('t_student.id'), primary_key=True),
    Column('c_id', Integer, ForeignKey('t_course.id'), primary_key=True)
)


# 2.创建多对多模型
# 学生表
class Student(Base):
    __tablename__ = 't_student'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))
    age = Column(Integer)

    # 4.定义relationship属性
    course_list = relationship('Course', backref='student_list', secondary=temp_tab)

    def __repr__(self):
        return "Student:name=%s" % self.name


# 课程表
class Course(Base):
    __tablename__ = 't_course'
    id = Column(Integer, primary_key=True, autoincrement=True)
    c_name = Column(String(50))  # 课程名字

    def __repr__(self):
        return "Course:c_name=%s" % self.c_name


# Base.metadata.drop_all()
# Base.metadata.create_all()

# 创建session对象
session = sessionmaker(engine)()


def save():
    s1 = Student(name='张三', age=22)
    s2 = Student(name='李四', age=22)

    c1 = Course(c_name='Python')
    c2 = Course(c_name='MySQL')

    s1.course_list.append(c1)
    s1.course_list.append(c2)
    s2.course_list.append(c1)
    s2.course_list.append(c2)

    session.add(s1)
    session.add(s2)

    session.commit()


# save()


def queryDate():
    s1 = session.query(Student).first()
    print(s1)
    print(s1.course_list)


queryDate()

insert image description here


Guess you like

Origin blog.csdn.net/m0_68744965/article/details/128444488