一、创建模型和表


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

  • 作者模型:一个作者有姓名和年龄。
  • 作者详细模型:把作者的详情放到详情表,手机号,家庭住址信息。
  • 作者详情模型 和 作者模型之间是一对一的关系(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 创建模型

from django.db import models

# 出版社
class Publish(models.Model):
# 主键
nid = models.AutoField(primary_key = True)
name = models.CharField(max_length = 55)
city = models.CharField(max_length = 55)
# email有特定的格式!
email = models.EmailField()
def __str__(self):
return 'nid: %s, name: %s, city: %s, email: %s\n' % (self.nid, self.name, self.city, self.email) # 作者详细
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key = True)
# 日期的格式
birthday = models.DateField()
# 手机号
telephone = models.BigIntegerField()
addr = models.CharField(max_length = 55)
def __str__(self):
return 'nid: %s, birthday: %s, telephone: %s, addr: %s\n' % (self.nid, self.birthday, self.telephone, self.addr) # 作者表
class Author(models.Model):
nid = models.AutoField(primary_key = True)
name = models.CharField(max_length = 55)
# 年龄,int 类型的小数字就可以
age = models.IntegerField() # 由于作者与作者详细表是一对一的关系:所以选择在作者表中这样建立外键
# 注意这里还是只写 authordetail 就可以了,_id 程序会自动给加的!
# 注意这里on_delete一定要加!而且to后面的表的名字要习惯性的加上1
# 一对一!
authordetail = models.OneToOneField(to = 'AuthorDetail', to_field = 'nid', on_delete = models.CASCADE)
def __str__(self):
return 'nid: %s, name: %s, age: %s, authordetail: %s\n' % (self.nid, self.name, self.age, self.authordetail) # 书籍
class Book(models.Model):
nid = models.AutoField(primary_key = True)
title = models.CharField(max_length = 55)
# 出版日期,日期格式
pub_date = models.DateField()
# 价格,最大位数5位,小数后保留两位
price = models.DecimalField(max_digits = 5, decimal_places = 2) # 与出版社表关联的字段 publish_id
# 注意自己写的时候只写publish就可以了!Django会自动补上_id
# 注意:on_delete必须要加上!!!而且to后面的表的名字要习惯性的加上1
# 注意 null=true表示允许为空值
# 一对多!
publish = models.ForeignKey(to = 'Publish', to_field = 'nid', on_delete = models.CASCADE,null = True) # 书跟作者是多对多的关系。理论上需要新建一张关系表。分别将其与书籍表与作者表关联起来!
authors = models.ManyToManyField(to = 'Author')
def __str__(self):
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)
"""
create table book2author(
id int primary_key auto_increment,
book_id int,0
author_id int,
foreign_key (book_id) references Book(nid),
foreign_key (author_id) references Author(nid),
);
"""

2 执行命令

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

3 增加数据

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

二、一对多外键


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

三、多对多外键


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

正反向的概念

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

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


# 1 查询书籍主键为1的出版社
book_obj = models.Book.objects.filter(pk = 1).first()
# 书查出版社 正向
res = book_obj.publish
print(res) # 2 查询书籍主键为2的作者 (多对多)
book_obj = models.Book.objects.filter(pk = 1).first()
# 书查作者 正向
author = book_obj.authors
print(author) # app.Author.None
authorAll = book_obj.authors.all() # <QuerySet [<Author: Author object>, <Author: Author object>]>
for obj in authorAll:
print(obj.name, obj.authordetail.telephone) # 3 查询作者 小美信息
author_obj = models.Author.objects.filter(name = '小美').first()
res = author_obj.authordetail
print(res) # 4 查询出版社是 立方出版社 的书
publish_obj = models.Publish.objects.filter(name = '立方出版社').first()
# 出版社查书 反向
bookSet = publish_obj.book_set
bookAll = publish_obj.book_set.all()
print(bookSet) # 立方出版社 app.Book.None
print(bookAll) # 5 查询作者是 小爱 写过的书
author_obj = models.Author.objects.filter(name = '小爱').first()
# 作者查书 反向
bookSet = author_obj.book_set
bookAll = author_obj.book_set.all()
print(bookSet) # app.Book.None
print(bookAll) # 6 查询手机号是 15368482379 的作者信息
author_detail_obj = models.AuthorDetail.objects.filter(telephone = 15368482379).first()
print(author_detail_obj)
res = author_detail_obj.author
print(res)

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



# 1 查询 小酒 的手机号
res = models.Author.objects.filter(name = '小酒').values('authordetail__telephone')
print(res)
# 反向
res = models.AuthorDetail.objects.filter(author__name = '小酒') # 拿作者姓名是 小酒 的作者详情
res = models.AuthorDetail.objects.filter(author__name = '小酒').values('telephone', 'author__name')
print(res) # 2 查询书籍主键为1的出版社名称和书的名称
res = models.Book.objects.filter(pk = 1).values('title', 'publish__name')
print(res)
# 反向
res = models.Publish.objects.filter(book__nid = 1).values('name', 'book__title')
print(res) # 3 查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk = 1).values('authors__name')
print(res)
# 反向
res = models.Author.objects.filter(book__nid = 1).values('name')
print(res) # 4 查询书籍主键是1的作者的手机号
book author authordetail
res = models.Book.objects.filter(pk = 1).values('authors__authordetail__telephone')
print(res) """
你只要掌握了正反向的概念
以及双下划线
那么你就可以无限制的跨表 """

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


# 练习: 查询 立方出版社 过的所有书籍的名字以及作者的姓名
# 正向查询
res = models.Book.objects.filter(publish__name = "立方出版社").values_list("title", "authors__name")
print(res) # 反向查询
res = models.Publish.objects.filter(name = "立方出版社").values_list("book__title", "book__authors__name")
print(res) # 练习: 手机号以 153 开头的作者出版过的所有书籍名称以及出版社名称
res = models.Book.objects.filter(authors__authordetail__telephone__regex="153").values_list("title", "publish__name")
print(res) res = models.Author.objects.filter(authordetail__telephone__startswith = "153").values("book__title", "book__publish__name")
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. 『现学现忘』Git后悔药 — 28、版本回退git reset --soft命令说明

    git reset --soft commit-id命令:回退到指定版本.(soft:柔软的) 该命令仅仅修改分支中的HEAD指针的位置,不会改变工作区与暂存区中的文件的版本. 实现上是只做了一件事情 ...

  2. MIT 6.824 Lab2C Raft之持久化

    书接上文Raft Part B | MIT 6.824 Lab2B Log Replication. 实验准备 实验代码:git://g.csail.mit.edu/6.824-golabs-2021 ...

  3. 手把手教你在netty中使用TCP协议请求DNS服务器

    目录 简介 DNS传输协议简介 DNS的IP地址 Do53/TCP在netty中的使用 搭建DNS netty client 发送DNS查询消息 DNS查询的消息处理 总结 简介 DNS的全称doma ...

  4. JavaScript进阶内容——DOM详解

    JavaScript进阶内容--DOM详解 当我们已经熟练掌握JavaScript的语法之后,我们就该进入更深层次的学习了 首先我们思考一下:JavaScript是用来做什么的? JavaScript ...

  5. 论文解读(MaskGAE)《MaskGAE: Masked Graph Modeling Meets Graph Autoencoders》

    论文信息 论文标题:MaskGAE: Masked Graph Modeling Meets Graph Autoencoders论文作者:Jintang Li, Ruofan Wu, Wangbin ...

  6. 我也是醉了,Eureka 延迟注册还有这个坑!

    Eureka 有个延迟注册的功能,也就是在服务启动成功之后不立刻注册到 Eureka Server,而是延迟一段时间再去注册,这样做的主要目的是因为虽然服务启动成功了,可能还有一些框架或者业务的代码没 ...

  7. Vxe-table 高亮当前行

    需求 1 :设置初始高亮 子组件: 父组件 需求 2 :高亮行的变化,需要把数据传递到兄弟组件中 解决办法:EventBus 参考链接: http://t.csdn.cn/iwOJc main.js ...

  8. websocket理解

    简介 在实际开发中,可能会出现一个需求场景,要求网页的数据可以实时更新.在这种情况下,我们一般会采用轮询的方式,间隔性获取数据,即通过定时器间隔性请求相应接口获取数据,此方式由于是不断请求服务器,资源 ...

  9. ES6中class方法及super关键字

    ES6 class中的一些问题 记录下class中的原型,实例,super之间的关系 //父类 class Dad { constructor(x, y) { this.x = 5; this.y = ...

  10. mysql常见用法

    查看连接数show processlist; 查看慢日志 show variables like '%slow_query_log%'; show variables like 'long_query ...