一、创建模型和表


假定下面这些概念、字段与关系:

  • 作者模型:一个作者有姓名和年龄。
  • 作者详细模型:把作者的详情放到详情表,手机号,家庭住址信息。
  • 作者详情模型 和 作者模型之间是一对一的关系(one-to-one)。
  • 出版社模型:出版社有名称,所在城市以及email。
  • 书籍模型: 书籍有书名和价格、出版日期。
  • 一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many)。
  • 一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
  • 书跟作者是多对多关系,利用Django 的建表语句,可以新生成一张“关系表”---> book2author。

ORM中的外键创建和mysql几乎一样,以创建图书表,出版社表,作者表和作者详情表。

两张表 关系 方法 外键位置
书与出版社 一对多关系 ForeignKey(to='出版社表') 一对多关系也是建在多的一方,建在书的表里
书与作者 多对多关系 ManyToManyField(to='作者表') 多对多关系,可以不用自己创建第三张表
作者与作者详情 一对一关系 OneToOneField=(to='作者详情表') 一对一关系,建在查询频率较高的表中,建在作者表里

三个关键字里面的参数,to用于指定跟哪张表有关系,自动关联主键。to_field\to_fields,也可以自己指定关联字段。

ManyToManyField不会在表中创建实际的字段,而是告诉 Django ORM 自动创建第三张关系表。

ForeignKey、OneToOneField会在字段的后面自动添加 _id 后缀,如果你在定义模型类的时候自己添加了该后缀那么迁移的时候还会添加,所以不要自己加下划线id后缀。

1 创建模型

  1. from django.db import models
  2. # 出版社
  3. class Publish(models.Model):
  4. # 主键
  5. nid = models.AutoField(primary_key = True)
  6. name = models.CharField(max_length = 55)
  7. city = models.CharField(max_length = 55)
  8. # email有特定的格式!
  9. email = models.EmailField()
  10. def __str__(self):
  11. return 'nid: %s, name: %s, city: %s, email: %s\n' % (self.nid, self.name, self.city, self.email)
  12. # 作者详细
  13. class AuthorDetail(models.Model):
  14. nid = models.AutoField(primary_key = True)
  15. # 日期的格式
  16. birthday = models.DateField()
  17. # 手机号
  18. telephone = models.BigIntegerField()
  19. addr = models.CharField(max_length = 55)
  20. def __str__(self):
  21. return 'nid: %s, birthday: %s, telephone: %s, addr: %s\n' % (self.nid, self.birthday, self.telephone, self.addr)
  22. # 作者表
  23. class Author(models.Model):
  24. nid = models.AutoField(primary_key = True)
  25. name = models.CharField(max_length = 55)
  26. # 年龄,int 类型的小数字就可以
  27. age = models.IntegerField()
  28. # 由于作者与作者详细表是一对一的关系:所以选择在作者表中这样建立外键
  29. # 注意这里还是只写 authordetail 就可以了,_id 程序会自动给加的!
  30. # 注意这里on_delete一定要加!而且to后面的表的名字要习惯性的加上1
  31. # 一对一!
  32. authordetail = models.OneToOneField(to = 'AuthorDetail', to_field = 'nid', on_delete = models.CASCADE)
  33. def __str__(self):
  34. return 'nid: %s, name: %s, age: %s, authordetail: %s\n' % (self.nid, self.name, self.age, self.authordetail)
  35. # 书籍
  36. class Book(models.Model):
  37. nid = models.AutoField(primary_key = True)
  38. title = models.CharField(max_length = 55)
  39. # 出版日期,日期格式
  40. pub_date = models.DateField()
  41. # 价格,最大位数5位,小数后保留两位
  42. price = models.DecimalField(max_digits = 5, decimal_places = 2)
  43. # 与出版社表关联的字段 publish_id
  44. # 注意自己写的时候只写publish就可以了!Django会自动补上_id
  45. # 注意:on_delete必须要加上!!!而且to后面的表的名字要习惯性的加上1
  46. # 注意 null=true表示允许为空值
  47. # 一对多!
  48. publish = models.ForeignKey(to = 'Publish', to_field = 'nid', on_delete = models.CASCADE,null = True)
  49. # 书跟作者是多对多的关系。理论上需要新建一张关系表。分别将其与书籍表与作者表关联起来!
  50. authors = models.ManyToManyField(to = 'Author')
  51. def __str__(self):
  52. return 'nid: %s, title: %s, pub_date: %s, price: %s, publish: %s, authors: %s\n' % (self.nid, self.title, self.pub_date, self.price, self.publish, self.authors)
  53. """
  54. create table book2author(
  55. id int primary_key auto_increment,
  56. book_id int,0
  57. author_id int,
  58. foreign_key (book_id) references Book(nid),
  59. foreign_key (author_id) references Author(nid),
  60. );
  61. """

2 执行命令

  1. python manage.py makemigrations
  2. python manage.py migrate
  3. # 查看一下数据库中是否生成了 "5" 张表

3 增加数据

  1. models.Publish.objects.create(name = '东方出版社',city = "beijing", email = "dongfang@beijing.com")
  2. models.Publish.objects.create(name = '京东出版社',city = "shanghai", email = "jingdong@shanghai.com")
  3. models.Publish.objects.create(name = '立方出版社',city = "guangzhou", email = "wuliu@guangzhou.com")
  4. models.Book.objects.create(title = 'Java', price = 199.93, pub_date = '2020-02-23', publish_id = 1)
  5. models.Book.objects.create(title = 'golang', price = 219.5, pub_date = '2019-09-17', publish_id = 2)
  6. models.Book.objects.create(title = 'python', price = 328.21, pub_date = '2020-11-15', publish_id = 3)
  7. models.Book.objects.create(title = 'django', price = 150.6, pub_date = '2018-08-26', publish_id = 1)
  8. models.Book.objects.create(title = 'gin', price = 110.23, pub_date = '2020-06-05', publish_id = 1)
  9. models.Book.objects.create(title = 'spring', price = 138.17, pub_date = '2020-03-16', publish_id = 3)
  10. models.AuthorDetail.objects.create(birthday = "1998-07-14", telephone = "13710398561", addr = "上海苏州")
  11. models.AuthorDetail.objects.create(birthday = "2003-10-11", telephone = "17764251377", addr = "深圳")
  12. models.AuthorDetail.objects.create(birthday = "1997-03-27", telephone = "15368482379", addr = "北京朝阳")
  13. models.AuthorDetail.objects.create(birthday = "2002-11-21", telephone = "17622488326", addr = "杭州")
  14. models.AuthorDetail.objects.create(birthday = "1998-05-16", telephone = "13642599728", addr = "成都")
  15. models.AuthorDetail.objects.create(birthday = "2005-09-08", telephone = "15367536245", addr = "湖南长沙")
  16. models.Author.objects.create(name = '小酒', age = 22, authordetail_id = 1)
  17. models.Author.objects.create(name = '小美', age = 19, authordetail_id = 2)
  18. models.Author.objects.create(name = '小花', age = 24, authordetail_id = 3)
  19. models.Author.objects.create(name = '小爱', age = 20, authordetail_id = 4)
  20. models.Author.objects.create(name = '小英', age = 23, authordetail_id = 5)
  21. models.Author.objects.create(name = '小雨', age = 17, authordetail_id = 6)

二、一对多外键


  1. # 一对多外键增删改查
  2. # 方法一
  3. publish_obj = models.Publish.objects.filter(nid = 1).first()
  4. models.Book.objects.create(title='beego', price = 100.99, pub_date='2020-03-26', publish = publish_obj)
  5. # 方法二
  6. models.Book.objects.create(title = 'dubbo', price = 98.79, pub_date = '2015-12-16', publish_id = 3)
  7. # 修改
  8. models.Book.objects.filter(pk = 5).update(publish_id = 2)
  9. publish_obj = models.Publish.objects.filter(pk = 1).first()
  10. models.Book.objects.filter(pk = 5).update(publish = publish_obj)
  11. # 删
  12. models.Publish.objects.filter(pk = 2).delete() # 级联删除

三、多对多外键


  1. # 多对多增删改查
  2. book_obj = models.Book.objects.filter(title = 'django').first()
  3. xiaojiu = models.Author.objects.filter(nid = 1).first()
  4. xiaoyu = models.Author.objects.filter(nid = 6).first()
  5. book_obj.authors.add(xiaojiu, xiaoyu) # 书籍name为django的书籍绑定一个主键为1和6的作者
  6. # book_obj.authors.add(2, 3)
  7. """
  8. add 给第三张关系表添加数据,括号内既可以传数字也可以传对象 并且都支持多个
  9. """
  10. # 查询主键为 4 的书籍的所有作者的名字
  11. bookVal = models.Book.objects.filter(nid = 4).first()
  12. rets = bookVal.authors.all().values('name')
  13. print(rets)
  14. # 结果: <QuerySet [{'name': '小酒'}, {'name': '小雨'}]>
  15. # 与这本书关联的所有作者对象集合 ---> QuerySet对象。[obj1, obj2,......]
  16. bookAll = models.Book.objects.filter(nid = 4).first()
  17. res = bookAll.authors.all()
  18. print(res)
  19. # 修改
  20. book_obj = models.Book.objects.filter(nid = 4).first()
  21. book_obj.authors.set([2, 3]) # 括号内必须给一个可迭代对象
  22. book_obj.authors.set([3]) # 括号内必须给一个可迭代对象
  23. author_obj = models.Author.objects.filter(pk = 4).first()
  24. author_obj1 = models.Author.objects.filter(pk = 5).first()
  25. book_obj.authors.set([author_obj, author_obj1]) # 括号内必须给一个可迭代对象
  26. """
  27. set 括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个
  28. """
  29. # 解除多对多关系,注意first得加
  30. book_obj = models.Book.objects.filter(nid = 4).first()
  31. # 注意这里的 4 代表 author_id
  32. book_obj.authors.remove(4)
  33. # 在第三张关系表中清空某个书籍与作者的绑定关系
  34. book_obj.authors.clear()
  35. """
  36. clear 括号内不要加任何参数
  37. """

正反向的概念

  1. # 正向: 外键字段在我手上那么,我查你就是正向
  2. # 反向: 外键字段如果不在手上,我查你就是反向
  3. # book >>> 外键字段在书那儿(正向) >>> publish
  4. # publish >>> 外键字段在书那儿(反向) >>> book
  5. # 一对一和多对多正反向的判断也是如此
  6. """
  7. 正向查询按字段
  8. 反向查询按表名小写
  9. _set
  10. ...
  11. """

五、子查询(基于对象的跨表查询)


  1. # 1 查询书籍主键为1的出版社
  2. book_obj = models.Book.objects.filter(pk = 1).first()
  3. # 书查出版社 正向
  4. res = book_obj.publish
  5. print(res)
  6. # 2 查询书籍主键为2的作者 (多对多)
  7. book_obj = models.Book.objects.filter(pk = 1).first()
  8. # 书查作者 正向
  9. author = book_obj.authors
  10. print(author) # app.Author.None
  11. authorAll = book_obj.authors.all() # <QuerySet [<Author: Author object>, <Author: Author object>]>
  12. for obj in authorAll:
  13. print(obj.name, obj.authordetail.telephone)
  14. # 3 查询作者 小美信息
  15. author_obj = models.Author.objects.filter(name = '小美').first()
  16. res = author_obj.authordetail
  17. print(res)
  18. # 4 查询出版社是 立方出版社 的书
  19. publish_obj = models.Publish.objects.filter(name = '立方出版社').first()
  20. # 出版社查书 反向
  21. bookSet = publish_obj.book_set
  22. bookAll = publish_obj.book_set.all()
  23. print(bookSet) # 立方出版社 app.Book.None
  24. print(bookAll)
  25. # 5 查询作者是 小爱 写过的书
  26. author_obj = models.Author.objects.filter(name = '小爱').first()
  27. # 作者查书 反向
  28. bookSet = author_obj.book_set
  29. bookAll = author_obj.book_set.all()
  30. print(bookSet) # app.Book.None
  31. print(bookAll)
  32. # 6 查询手机号是 15368482379 的作者信息
  33. author_detail_obj = models.AuthorDetail.objects.filter(telephone = 15368482379).first()
  34. print(author_detail_obj)
  35. res = author_detail_obj.author
  36. print(res)

六、联表查询(基于双下划线的跨表查询)



  1. # 1 查询 小酒 的手机号
  2. res = models.Author.objects.filter(name = '小酒').values('authordetail__telephone')
  3. print(res)
  4. # 反向
  5. res = models.AuthorDetail.objects.filter(author__name = '小酒') # 拿作者姓名是 小酒 的作者详情
  6. res = models.AuthorDetail.objects.filter(author__name = '小酒').values('telephone', 'author__name')
  7. print(res)
  8. # 2 查询书籍主键为1的出版社名称和书的名称
  9. res = models.Book.objects.filter(pk = 1).values('title', 'publish__name')
  10. print(res)
  11. # 反向
  12. res = models.Publish.objects.filter(book__nid = 1).values('name', 'book__title')
  13. print(res)
  14. # 3 查询书籍主键为1的作者姓名
  15. res = models.Book.objects.filter(pk = 1).values('authors__name')
  16. print(res)
  17. # 反向
  18. res = models.Author.objects.filter(book__nid = 1).values('name')
  19. print(res)
  20. # 4 查询书籍主键是1的作者的手机号
  21. book author authordetail
  22. res = models.Book.objects.filter(pk = 1).values('authors__authordetail__telephone')
  23. print(res)
  24. """
  25. 你只要掌握了正反向的概念
  26. 以及双下划线
  27. 那么你就可以无限制的跨表
  28. """

七、进阶练习(连续跨表)


  1. # 练习: 查询 立方出版社 过的所有书籍的名字以及作者的姓名
  2. # 正向查询
  3. res = models.Book.objects.filter(publish__name = "立方出版社").values_list("title", "authors__name")
  4. print(res)
  5. # 反向查询
  6. res = models.Publish.objects.filter(name = "立方出版社").values_list("book__title", "book__authors__name")
  7. print(res)
  8. # 练习: 手机号以 153 开头的作者出版过的所有书籍名称以及出版社名称
  9. res = models.Book.objects.filter(authors__authordetail__telephone__regex="153").values_list("title", "publish__name")
  10. print(res)
  11. res = models.Author.objects.filter(authordetail__telephone__startswith = "153").values("book__title", "book__publish__name")
  12. print(res)

Django ORM 实现数据的多表 增删改查的更多相关文章

  1. Django ORM 实现数据的单表 增删改查

    一.配置环境 1 Django 连接数据库(MySQL) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME' ...

  2. Django框架(八)--单表增删改查,在Python脚本中调用Django环境

    一.数据库连接配置 如果连接的是pycharm默认的Sqlite,不用改动,使用默认配置即可 如果连接mysql,需要在配置文件中的setting中进行配置: 将DATABASES={} 更新为 DA ...

  3. Django框架(九)—— 单表增删改查,在Python脚本中调用Django环境

    目录 单表增删改查,在Python脚本中调用Django环境 一.数据库连接配置 二.orm创建表和字段 三.单表增删改查 1.增加数据 2.删除数据 3.修改数据 4.查询数据 四.在Python脚 ...

  4. Vc数据库编程基础MySql数据库的表增删改查数据

    Vc数据库编程基础MySql数据库的表增删改查数据 一丶表操作命令 1.查看表中所有数据 select * from 表名 2.为表中所有的字段添加数据 insert into 表名( 字段1,字段2 ...

  5. GZFramwork数据库层《一》普通表增删改查

    运行结果:     使用代码生成器(GZCodeGenerate)生成tb_MyUser的Model 生成器源代码下载地址: https://github.com/GarsonZhang/GZCode ...

  6. GZFramwork数据库层《三》普通主从表增删改查

    运行结果: 使用代码生成器(GZCodeGenerate)生成tb_Cusomer和tb_CusomerDetail的Model 生成器源代码下载地址: https://github.com/Gars ...

  7. JQuery Easyui/TopJUI 用JS创建数据表格并实现增删改查功能

    JQuery Easyui/TopJUI 用JS创建数据表格并实现增删改查功能 html <table id="productDg"></table> &l ...

  8. GZFramwork数据库层《四》单据主从表增删改查

    同GZFramwork数据库层<三>普通主从表增删改查 不同之处在于:实例 修改为: 直接上效果: 本系列项目源码下载地址:https://github.com/GarsonZhang/G ...

  9. GZFramwork数据库层《二》单据表增删改查(自动生成单据号码)

    运行效果: 使用代码生成器(GZCodeGenerate)生成tb_EmpLeave的Model 生成器源代码下载地址: https://github.com/GarsonZhang/GZCodeGe ...

随机推荐

  1. 当在命令行输入"pip install xxx"

    当输入"pip install xxx"时发生了什么 不知道你在下载一些包的时候有没有什么疑惑,输入了"pip install xxx" ,系统是如何找到对应的 ...

  2. 记一次 .NET 某RFID标签管理系统 CPU 暴涨分析

    一:背景 1. 讲故事 前段时间有位朋友说他的程序 CPU 出现了暴涨现象,由于程序是买来的,所以问题就比较棘手了,那既然找到我,就想办法帮朋友找出来吧,分析下来,问题比较经典,有必要和大家做一下分享 ...

  3. 关于Tornado5.1:到底是真实的异步和还是虚假的异步

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_107 我们知道Tornado 优秀的大并发处理能力得益于它的 web server 从底层开始就自己实现了一整套基于 epoll ...

  4. Win10系统下安装编辑器之神(The God of Editor)Vim并且构建Python生态开发环境(2020年最新攻略)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_160 众神殿内,依次坐着Editplus.Atom.Sublime.Vscode.JetBrains家族.Comodo等等一众编辑 ...

  5. 解决 Vue 部署在域名子路由 问题

    我们先看下官方说明 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 https://www.my-app.com/ .如果应用被部署在一个子路径上,你就需要用这个选项指定 ...

  6. Vue 路由的一些复杂配置

    1 # 一.路由的props参数 2 export default new VueRouter({ 3 routes:[ 4 { 5 name:'guanyu', // 命名路由 6 path:'/a ...

  7. JDBC与ODBC的区别

    JDBC简介JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,它是Java十三个规范之一.可以为多种关系数据库提供统一访 ...

  8. devops-2:Jenkins的使用及Pipeline语法讲解

    DevOps-Jenkins Jenkins简介 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续 ...

  9. V8中的快慢数组(附源码、图文更易理解😃)

    接上一篇掘金 V8 中的快慢属性,本篇分析V8 中的快慢数组,了解数组全填充还是带孔.快慢数组.快慢转化.动态扩缩容等等.其实很多语言底层都采用类似的处理方式,比如:Golang中切片的append操 ...

  10. placeholder 设置换行三种方式

    在 html 中编写代码时保留代码换行 <textarea name="" id="" cols="30" rows="10 ...