SQLAlchemy03 /外键、连表关系

1、外键

  • 外键简述

    使用SQLAlchemy创建外键非常简单。在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。从表中外键的字段,必须和父表的主键字段类型保持一致。

  • 示例代码如下:

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. class Article(Base):
    6. __tablename__ = 'article'
    7. id = Column(Integer,primary_key=True,autoincrement=True)
    8. title = Column(String(50),nullable=False)
    9. content = Column(Text,nullable=False)
    10. uid = Column(Integer,ForeignKey("user.id"))
  • 外键约束有以下几项:

    1. 1. RESTRICT:父表数据被删除,会阻止删除。默认就是这一项。
    2. 2. NO ACTION:在MySQL中,同RESTRICT
    3. 3. CASCADE:级联删除。
    4. 4. SET NULL:父表数据被删除,子表数据会设置为NULL

2、ORM关系以及一对多

  • 简述

    mysql级别的外键,还不够ORM,必须拿到一个表的外键,然后通过这个外键再去另外一张表中查找,这样太麻烦了。SQLAlchemy提供了一个relationship,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问得到了。

  • 示例代码:

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. # articles = relationship("Article")
    6. def __repr__(self):
    7. return "<User(username:%s)>" % self.username
    8. class Article(Base):
    9. __tablename__ = 'article'
    10. id = Column(Integer,primary_key=True,autoincrement=True)
    11. title = Column(String(50),nullable=False)
    12. content = Column(Text,nullable=False)
    13. uid = Column(Integer,ForeignKey("user.id"))
    14. author = relationship("User",backref="articles")
    15. # 创建一对多数据
    16. user = User(username='zhangsan')
    17. session.add(user)
    18. session.commit()
    19. article = Article(title='abc',content='123',uid=1)
    20. session.add(article)
    21. session.commit()
    22. # 查询一对多数据
    23. article = session.query(Article).first()
    24. uid = article.uid
    25. print(article)
    26. user = session.query(User).get(uid)
    27. print(user)
  • 另外,可以通过backref来指定反向访问的属性名称。articles是有多个。他们之间的关系是一个一对多的关系

3、一对一的关系

  • 简述

    在sqlalchemy中,如果想要将两个模型映射成一对一的关系,那么应该在父模型中,指定引用的时候,要传递一个uselist=False这个参数进去。就是告诉父模型,以后引用这个从模型的时候,不再是一个列表了,而是一个对象了。

  • 示例代码如下:

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. extend = relationship("UserExtend",uselist=False)
    6. def __repr__(self):
    7. return "<User(username:%s)>" % self.username
    8. class UserExtend(Base):
    9. __tablename__ = 'user_extend'
    10. id = Column(Integer, primary_key=True, autoincrement=True)
    11. school = Column(String(50))
    12. uid = Column(Integer,ForeignKey("user.id"))
    13. user = relationship("User",backref="extend")

    简化代码:可以借助sqlalchemy.orm.backref来简化代码

    1. from sqlalchemy.orm import sessionmaker,relationship,backref
    2. class User(Base):
    3. __tablename__ = 'user'
    4. id = Column(Integer,primary_key=True,autoincrement=True)
    5. username = Column(String(50),nullable=False)
    6. # 方式一:
    7. # extend = relationship("UserExtend",uselist=False)
    8. def __repr__(self):
    9. return "<User(username:%s)>" % self.username
    10. class UserExtend(Base):
    11. __tablename__ = 'user_extend'
    12. id = Column(Integer, primary_key=True, autoincrement=True)
    13. school = Column(String(50))
    14. uid = Column(Integer,ForeignKey("user.id"))
    15. # 方式二:
    16. user = relationship("User",backref=backref("extend",uselist=False))
    17. # 创建一对一数据
    18. user = User(username='zhangsan')
    19. extend1 = UserExtend(school='qinghua daxue')
    20. user.extend = extend1
    21. session.add(user)
    22. session.commit()
    23. # 查看一对一数据
    24. # 可以直接根据属性去查询对应的数据

4、多对多的关系

  • 简述

    1. 多对多的关系需要通过一张中间表来绑定他们之间的关系。
    2. 先把两个需要做多对多的模型定义出来
    3. 使用Table定义一个中间表,中间表一般就是包含两个模型的外键字段就可以了,并且让他们两个来作为一个“复合主键”。
    4. 在两个需要做多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,需要传入一个secondary=中间表。
  • 代码示例:

    1. article_tag = Table(
    2. "article_tag",
    3. Base.metadata,
    4. Column("article_id",Integer,ForeignKey("article.id"),primary_key=True),
    5. Column("tag_id",Integer,ForeignKey("tag.id"),primary_key=True)
    6. )
    7. class Article(Base):
    8. __tablename__ = 'article'
    9. id = Column(Integer,primary_key=True,autoincrement=True)
    10. title = Column(String(50),nullable=False)
    11. # 方式一:
    12. # tags = relationship("Tag",backref="articles",secondary=article_tag)
    13. def __repr__(self):
    14. return "<Article(title:%s)>" % self.title
    15. class Tag(Base):
    16. __tablename__ = 'tag'
    17. id = Column(Integer, primary_key=True, autoincrement=True)
    18. name = Column(String(50), nullable=False)
    19. # 方式二:
    20. articles = relationship("Article",backref="tags",secondary=article_tag)
    21. def __repr__(self):
    22. return "<Tag(name:%s)>" % self.name
    23. # 添加多对多数据
    24. article1 = Article(title="article1")
    25. article2 = Article(title="article2")
    26. tag1 = Tag(name='tag1')
    27. tag2 = Tag(name='tag2')
    28. article1.tags.append(tag1)
    29. article1.tags.append(tag2)
    30. article2.tags.append(tag1)
    31. article2.tags.append(tag2)
    32. session.add(article1)
    33. session.add(article2)
    34. session.commit()
    35. # 查询多对多数据
    36. article = session.query(Article).first()
    37. print(article.tags)
    38. tag = session.query(Tag).first()
    39. print(tag.articles)

5、ORM层面的删除数据

  • 简述:

    ORM层面删除数据,会无视mysql级别的外键约束。直接会将对应的数据删除,然后将从表中的那个外键设置为NULL。如果想要避免这种行为,应该将从表中的外键的nullable=False

  • 代码示例:

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. class Article(Base):
    6. __tablename__ = 'article'
    7. id = Column(Integer, primary_key=True, autoincrement=True)
    8. title = Column(String(50),nullable=False)
    9. uid = Column(Integer,ForeignKey("user.id"),nullable=False)
    10. author = relationship("User",backref='articles')
    11. # Base.metadata.drop_all()
    12. # Base.metadata.create_all()
    13. #
    14. # user = User(username='zhiliao')
    15. # article = Article(title='hello world')
    16. # article.author = user
    17. # session.add(article)
    18. # session.commit()
    19. # orm层面的删除,删除User时Article表关联的字段会置为NULL
    20. # 将uid设置为nullable=False,就不会造成上面的orm层面的删除
    21. user = session.query(User).first()
    22. session.delete(user)
    23. session.commit()

6、ORM层面的CASCADE

  • 在SQLAlchemy,只要将一个数据添加到session中,和他相关联的数据都可以一起存入到数据库中了。这些是怎么设置的呢?其实是通过relationship的时候,有一个关键字参数cascade可以设置这些属性:

    1. save-update:默认选项。在添加一条数据的时候,会把其他和他相关联的数据都添加到数据库中。这种行为就是save-update属性影响的。
    2. delete:表示当删除某一个模型中的数据的时候,是否也删掉使用relationship和他关联的数据。
    3. delete-orphan:表示当对一个ORM对象解除了父表中的关联对象的时候,自己便会被删除掉。当然如果父表中的数据被删除,自己也会被删除。这个选项只能用在一对多上,不能用在多对多以及多对一上。并且还需要在子模型中的relationship中,增加一个single_parent=True的参数。
    4. merge:默认选项。当在使用session.merge,合并一个对象的时候,会将使用了relationship相关联的对象也进行merge操作。
    5. expunge:移除操作的时候,会将相关联的对象也进行移除。这个操作只是从session中移除,并不会真正的从数据库中删除。
    6. all:是对save-update, merge, refresh-expire, expunge, delete几种的缩写。
  • 代码示例:

    示例一:正常添加数据,默认cascade="save-update"

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. class Article(Base):
    6. __tablename__ = 'article'
    7. id = Column(Integer, primary_key=True, autoincrement=True)
    8. title = Column(String(50), nullable=False)
    9. uid = Column(Integer,ForeignKey("user.id"),nullable=False)
    10. author = relationship("User",backref="articles")
    11. Base.metadata.drop_all()
    12. Base.metadata.create_all()
    13. user = User(username='zhangsan')
    14. article = Article(title='title')
    15. article.author = user
    16. session.add(user)
    17. session.commit()

    示例二:cascade=""

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. class Article(Base):
    6. __tablename__ = 'article'
    7. id = Column(Integer, primary_key=True, autoincrement=True)
    8. title = Column(String(50), nullable=False)
    9. uid = Column(Integer,ForeignKey("user.id"),nullable=False)
    10. author = relationship("User",backref="articles"cascade="")
    11. Base.metadata.drop_all()
    12. Base.metadata.create_all()
    13. user = User(username='zhangsan')
    14. article = Article(title='title')
    15. article.author = user
    16. session.add(user) # 这样只会添加user不会添加article
    17. session.commit()

    示例三:cascade="delete"

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. class Article(Base):
    6. __tablename__ = 'article'
    7. id = Column(Integer, primary_key=True, autoincrement=True)
    8. title = Column(String(50), nullable=False)
    9. uid = Column(Integer,ForeignKey("user.id"),nullable=False)
    10. author = relationship("User",backref="articles"cascade="save-update,delete")
    11. # 删除该文章,会将该文章对应的User删除
    12. def my_init_db():
    13. """ 用来初始化数据 """
    14. Base.metadata.drop_all()
    15. Base.metadata.create_all()
    16. user = User(username='zhangsan')
    17. article = Article(title='title')
    18. article.author = user
    19. comment = Comment(content='xxx')
    20. comment.author = user
    21. session.add(comment)
    22. session.add(article)
    23. session.commit()
    24. def operation():
    25. article = session.query(Article).first()
    26. session.delete(article)
    27. session.commit()
    28. if __name__ == '__main__':
    29. # my_init_db()
    30. operation()

    示例四:cascade="delete-orphan"删除孤儿数据,结合single_parent=True使用

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(Integer,primary_key=True,autoincrement=True)
    4. username = Column(String(50),nullable=False)
    5. class Article(Base):
    6. __tablename__ = 'article'
    7. id = Column(Integer, primary_key=True, autoincrement=True)
    8. title = Column(String(50), nullable=False)
    9. uid = Column(Integer,ForeignKey("user.id"),nullable=False)
    10. author = relationship("User",backref=backref("articles",cascade="save-update,delete,delete-orphan"),cascade="save-update",single_parent=True)
    11. def my_init_db():
    12. Base.metadata.drop_all()
    13. Base.metadata.create_all()
    14. user = User(username='zhangsan')
    15. article = Article(title='title')
    16. article.author = user
    17. session.add(article)
    18. session.commit()
    19. def operation():
    20. user = session.query(User).first()
    21. user.articles = []
    22. session.commit()
    23. session.commit()
    24. if __name__ == '__main__':
    25. # my_init_db()
    26. operation()

SQLAlchemy03 /外键、连表关系的更多相关文章

  1. Django(15)外键和表关系

    外键删除操作 如果一个模型使用了外键.那么在对方那个模型被删掉后,该进行什么样的操作.可以通过on_delete来指定.可以指定的类型如下: CASCADE:级联操作.如果外键对应的那条数据被删除了, ...

  2. oracle查询某张表的外键,并用 truncate 命令有外键的表中的数据

    注:本文来源于<oracle查询某张表的外键(最终解决办法)> 一:几个查询表外键的脚本 select b.table_name, b.column_name from user_cons ...

  3. 主外键多表查询demo

    https://www.cnblogs.com/DragonFire/p/6949767.html mySQL练习-主外键多表查询 MySQL练习-主外键多表查询 练习: 1.建立表关系: 请创建如下 ...

  4. 删除带外键的表【foreign key constraint fails】报错

    title: 删除带外键的表[foreign key constraint fails]报错 date: 2018-08-02 21:59:06 tags: 数据库 --- 遥想当时正在学hibern ...

  5. mysql外键与表查询

    目录 自增特性 外键 外键关系 外键创建 外键的约束效果 级联更新级联删除 多对多关系 一对一关系 表查询关键字 select与from where筛选 group by分组 练习 关系练习 查询练习 ...

  6. 【Hibernate】无外键多表查询

    无外键多表查询时编写hql,直接使用逗号分隔表,where作为联合查询条件进行查询.查询出来的结果可为两种,List<List<Object>>或者List<Map< ...

  7. Django中ORM外键和表的关系(Django编程-4)

    外键 在MySQL中,表有两种引擎,一种是InnoDB,另外一种是myisam.如果使用的是InnoDB引擎,是支持外键约束的.外键的存在使得ORM框架在处理表关系的时候异常的强大.因此这里我们首先来 ...

  8. MySQ-表关系-外键-修改表结构-复制表-03

    目录 前言 不合理的表结构(案例) 带来的问题 如何解决问题? 如何确定表关系? 表关系 一对多 多对多 一对一 应用场景 判断表关系最简单的语法 三种关系常见案例 如何建立表关系? 外键 forei ...

  9. Python Django orm操作数据库笔记之外键和表关系

    外键 在MySQL中,表有两种引擎,一种是InnoDB,另外一种是myisam.如果使用的是InnoDB引擎,是支持外键约束的. 外键的使用 使用外键前需要先确保相应外键已存储在数据库中(flask中 ...

随机推荐

  1. 小师妹学JavaIO之:NIO中那些奇怪的Buffer

    目录 简介 Buffer的分类 Big Endian 和 Little Endian aligned内存对齐 总结 简介 妖魔鬼怪快快显形,今天F师兄帮助小师妹来斩妖除魔啦,什么BufferB,Buf ...

  2. 线上服务的FGC问题排查,看这篇就够了!

    线上服务的GC问题,是Java程序非常典型的一类问题,非常考验工程师排查问题的能力.同时,几乎是面试必考题,但是能真正答好此题的人并不多,要么原理没吃透,要么缺乏实战经验. 过去半年时间里,我们的广告 ...

  3. turtle 画一朵花

    操纵海龟绘图有着许多的命令,这些命令可以划分为两种:一种为运动命令,一种为画笔控制命令1. 运动命令:forward(degree)  #向前移动距离degree代表距离backward(degree ...

  4. ado.net Web前端:关于JavaScript知识点的简单梳理

    学习js:1.htmml2.cssjs+html+css == html5 js的组成:1).ecamscript ES是js的标准,js 是es 的实现2)文档对象模型(Document Objec ...

  5. 几款一元单片机对比:CMS8S5880、STM8S003、N76E003

    大概17年开始,STM8S003的价格被贸易商炒货,变得很不稳定,一度上涨到2~3元,因为市场需求大增,小家电.无线充和一些简单功能的产品,本人就有在空气净化器.433M触摸开关.数据收发模块.红外控 ...

  6. C# 泛型的基本知识,以及什么是泛型?

    1.1 泛型概述 1.1.1 泛型广泛用于容器(collections) 1.1.2 命名空间System.Collections.Generic 1.2 泛型的优点. 以前类型的泛化(general ...

  7. 使用git畅游代码的海洋

    如果把互联网上的纷繁代码比作一片海洋,那么git就是在这片海洋上航行的船只,正所谓“水可载舟,亦可覆舟”,git使用恰当可以远征星辰,不然可能会坠入无穷无尽的代码海洋无法自拔.书回正传,我们的征途是星 ...

  8. IDEA 2019版本永久破解教程

    1.第一步解压文件(文件网盘下载链接在下面) 2.运行IDEA安装包 3.点击Next 4.注意安装位置文件夹不要带中文-选择好点击Next 5.勾选64-bit launcher,勾选.java,点 ...

  9. 入门大数据---Hive是什么?

    这篇文章主要介绍Hive的概念. 简介: Hive中文名叫数据仓库管理系统,之前我们操作MapReduce必须通过编写代码或者通过特殊命令来实现,有了Hive我们通过常用的SQL语句就能操作MapRe ...

  10. Python并发编程理论篇

    Python并发编程理论篇 前言 其实关于Python的并发编程是比较难写的一章,因为涉及到的知识很复杂并且理论偏多,所以在这里我尽量的用一些非常简明的语言来尽可能的将它描述清楚,在学习之前首先要记住 ...