美文网首页
Python-SQLAlchemy的ORM(4)

Python-SQLAlchemy的ORM(4)

作者: 木叶苍蓝 | 来源:发表于2019-12-31 20:49 被阅读0次

    来源:本文章摘抄于《知了课堂》,本人也是知了课堂的学生

    相关

    Python-SQLAlchemy介绍和基本使用
    Python-SQLAlchemy(1)
    Python-SQLAlchemy(2)
    Python-SQLAlchemy(3)
    Python-SQLAlchemy(4)
    Python-SQLAlchemy(5)

    表关系:

    表之间的关系存在三种:一对一,一对多,多对多。而 SQLAlchemy 中的 ORM 也可以模拟这三种关系。因为一对一其是在 SQLAlchemy 中底层是通过一对多的方式模拟的,所以先看一对多的关系:

    外键:

    在 Mysql 中,外键可以让表之间的关系更加紧密。而SQLAlchemy 同样也是支持外键的。通过 ForeignKey 类来实现,并且可以指定表的外键约束。相关代码如下:

        class Article(Base):
              __tablename__ = 'article'
              id = Column(Integer, primary_key=True, autoincrement=True)
              title = Column(String(50), nullable=False)
              content = Column(Text, nullable=False)
              uid = Column(Integer, ForeignKey('user.id'))
              
              def __repr__(self):
                    return "<Article(title:%s)>"%self.title
    
      class User(Base):
            __tablename__ = "user"
            id = Column(Integer, primary_key=True, autoincrement=True)
            username = Column(String(50), nullable=False)
    
    外键约束有以下几项:
    1. RESTRICT:父表数据被删除,会阻止删除。默认就是这一项。
    2. NO ACTION:在 MySQL中,同 RESTRICT
    3. CASCADE:级联删除
    4. SET NULL:父表数据被删除,子表数据会设置为NULL

    一对多:

    拿之前的 User 表为例,假如现在添加一个功能,要保存用户的邮箱账号,并且邮箱账号可以有多个,这时候就必须创建一个新的表,用来存储用户的邮箱,然后通过user.id来作为外键进行引用,先看邮箱表的实现:

        from sqlalchemy import ForeignKey
        from sqlalchemy.orm import relationship
    
        class Address(Base):
              __tablename__ = 'address'
              id = Column(Integer, primary_key=True)
              email_address = Column(String(50), nullable=False)
              # User 表的外键,指定外键的时候,是使用的数据库表的名称,而不是类名
              user_id = Column(Integer, ForeignKey('users.id'))
              # 在 ORM 层面绑定两者之间的关系,第一个参数是绑定的表的类名
              # 第二个参数back_populates是通过User反向访问的字段名称
              user = relationship('user', back_populates='addresses')
    
              def __repr__(self):
                    return '<Address(email_address=%s)>'%self.email_address
    
    # 重新修改User表,添加addresses字段,引用了Address表的主键
      class User(Base):
            __tablename__ = 'users'
            id = Column(Integer, primary_key=True)
            name = Column(String(50))
            fullname = Column(String(50))
            password = Column(String(100))
            # 在 ORM 层面绑定和 `Address` 表的关系
            addresses = relationship('address', order_by=Address.id, back_populates='user')
    

    其中,在User表中添加的addresses字段,可以通过User.addresses 来访问和这个user相关的所有address。在Address表中的user字段,也可以通过Address.user来访问这个user。达到了双向绑定。表关系已经建立好了,接下来应该对其进行操作:

        jack = User(name='jack', fullname='Jack Bean', password='123456')
        jack.addresses = [Address(email_address='jack@google.com'), Address(email_address='j25@google.com')]
        session.add(jack)
        session.commit()
    

    首先,创建一个用户,然后对这个jack 用户添加两个邮箱,最后再提交到数据库中,可以看到这里操作Address并没有直接进行保存,而是先添加到用户里面,在保存。

    一对一:

    一对一其实就是一对多的特殊情况,从以上的一对多例子中不难发现,一对应的User表,而多对应的是 Address,也就是说一个User 对象有多个Address,因此要将一对多转换成一对一,只要设置一个User对象对应一个Address对象即可,看以下例子:

        class User(Base):
               __tablename__ = 'users'
              id = Column(Integer, primary_key=True)
              name = Column(String(50))
              fullname = Column(String(50))
              password = Column(String(50))
              # 设置userlist关键字参数为False
              addresses = relationship("addresses", back_populates='user', userlist=False)
    
        class Address(Base):
              __tablename__ = 'addresses'
              id = Column(Integer, primary_key=True)
              email_address = Column(String(50))
              user_id = Column(Integer, ForeignKey('user.id'))
              user = relationship('user', back_populates='addresses')
    

    从上面的例子可以看到,只要在User表中的addresses字段上添加userlist=False就可以达到一对一的效果。设置了一对一的效果后,就不能添加多个邮箱到user.addresses字段了,只能添加一个。

        user.addresses = Address(email_address='ed@google.com')
    

    多对多:

    多对多需要一个中间表来作为连接,同理在sqlalchemy中的orm也需要一个中间表。假如现在有一个Teacher和一个Classes表,即老师和班级,一个老师可以教多个班级,一个班级也可以有多个老师,是一种典型的多对多的关系,那么通过sqlalchemyORM的实现方法如下:

        association_table = Table('teacher_classes', Base.metadata, Column('teacher_id', Integer, ForeignKey('teacher_id')), Column('classes_id', Integer, Foreignkey('classes.id')))
    
        class Teacher(Base):
              __tablename__ = 'teacher'
              id = Column(Integer, primary_key=True)
              tno = Column(String(10))
              name = Column(String(50))
              age = Column(Integer)
              classes = relationship('classes', secondary=association_table, back_populates='teachers')
    
        class Classes(Base):
              __tablename__ = 'classes'
              id = Column(Integer, primary_key=True)
              cno = Column(String(10))
              name = Column(String(50))
              teachers = relationship('teacher', secondary=association_table, back_populates='classes')
    

    要创建一个多对多的关系表,首先需要一个中间表,通过Table来创建一个中间表。上例中第一个参数teacher_classes代表的是中间表的表名,第二个参数是 Base 的元类,第三个和第四个参数就是要连接的两个表,其中Column第一个参数是表示连接表的外键名,第二个参数表示这个外键类型,第三个参数表示外键的表名和字段。
    创建完中间表以后,还需要在两个表中进行绑定,比如在teacher中有一个classes属性,来绑定classes表,并且通过secondary参数来连接中间表。同理,classes表连接, teacher也是如此。定义完类之后,添加数据:

        teacher1 = Teacher(tnp='t11', name='wang', age=28)
        teacher1 = Teacher(tnp='t22', name='li', age=30)
        classes1 = Classes(cnp='c11', name='203')
        classes2 = Classes(cnp='c22', name='204')
        teacher1.classes = [classes1, classes2]
        teacher2.classes = [classes1, classes2]
        classes1.teachers = [teacher1, teacher2]
        classes2.teachers = [teacher1, teacher2]
        
        session.add(teacher1)
        session.add(teacher2)
        session.add(classes1)
        session.add(classes2)
    

    相关文章

      网友评论

          本文标题:Python-SQLAlchemy的ORM(4)

          本文链接:https://www.haomeiwen.com/subject/molioctx.html