一对一
: 一个人对应一个身份证号码,数据字段设置 unique。
一对多
: 一个家庭有多个人,一般通过外键来实现。
多对多
: 一个学生有多门课程,一个课程有很多学生,一般通过第三个表来实现关联。
接下来我们来看下多表多实例。
class
Book
(
models.
Model
)
:
title
=
models.
CharField
(
max_length
=
32
)
price
=
models.
DecimalField
(
max_digits
=
5
,
decimal_places
=
2
)
pub_date
=
models.
DateField
(
)
publish
=
models.
ForeignKey
(
"Publish"
,
on_delete
=
models.
CASCADE
)
authors
=
models.
ManyToManyField
(
"Author"
)
class
Publish
(
models.
Model
)
:
name
=
models.
CharField
(
max_length
=
32
)
city
=
models.
CharField
(
max_length
=
64
)
email
=
models.
EmailField
(
)
class
Author
(
models.
Model
)
:
name
=
models.
CharField
(
max_length
=
32
)
age
=
models.
SmallIntegerField
(
)
au_detail
=
models.
OneToOneField
(
"AuthorDetail"
,
on_delete
=
models.
CASCADE
)
class
AuthorDetail
(
models.
Model
)
:
gender_choices
=
(
(
0
,
"女"
)
,
(
1
,
"男"
)
,
(
2
,
"保密"
)
,
gender
=
models.
SmallIntegerField
(
choices
=
gender_choices
)
tel
=
models.
CharField
(
max_length
=
32
)
addr
=
models.
CharField
(
max_length
=
64
)
birthday
=
models.
DateField
(
)
1、EmailField 数据类型是邮箱格式,底层继承 CharField,进行了封装,相当于 MySQL 中的 varchar。
2、Django1.1 版本不需要联级删除:on_delete=models.CASCADE,Django2.2 需要。
3、一般不需要设置联级更新.
4、外键在一对多的多中设置:
models.ForeignKey("关联类名", on_delete=models.CASCADE)
。
5、OneToOneField = ForeignKey(...,unique=True)设置一对一。
6、若有模型类存在外键,创建数据时,要先创建外键关联的模型类的数据,不然创建包含外键的模型类的数据时,外键的关联模型类的数据会找不到。
书籍表 Book
:title 、 price 、 pub_date 、 publish(外键,多对一) 、 authors(多对多)
出版社表 Publish
:name 、 city 、 email
作者表 Author
:name 、 age 、 au_detail(一对一)
作者详情表 AuthorDetail
:gender 、 tel 、 addr 、 birthday
以下是表格关联说明:
我们在 MySQL 中执行以下 SQL 插入操作:
insert into app01_publish(name,city,email) values ("华山出版社", "华山", "hs@163.com"), ("明教出版社", "黑木崖", "mj@163.com")
# 先插入 authordetail 表中多数据
insert into app01_authordetail(gender,tel,addr,birthday) values (1,13432335433,"华山","1994-5-23"), (1,13943454554,"黑木崖","1961-8-13"), (0,13878934322,"黑木崖","1996-5-20")
# 再将数据插入 author,这样 author 才能找到 authordetail
insert into app01_author(name,age,au_detail_id) values ("令狐冲",25,1), ("任我行",58,2), ("任盈盈",23,3)
ORM - 添加数据
一对多(外键 ForeignKey)
方式一:
传对象的形式,返回值的数据类型是对象,书籍对象。
a. 获取出版社对象
b. 给书籍的出版社属性 pulish 传出版社对象
app01/views.py 文件代码:
def
add_book
(
request
)
:
# 获取出版社对象
pub_obj
=
models.
Publish
.
objects
.
filter
(
pk
=
1
)
.
first
(
)
# 给书籍的出版社属性publish传出版社对象
book
=
models.
Book
.
objects
.
create
(
title
=
"菜鸟教程"
,
price
=
200
,
pub_date
=
"2010-10-10"
,
publish
=
pub_obj
)
print
(
book
,
type
(
book
)
)
return
HttpResponse
(
book
)
方式二: 传对象 id 的形式(由于传过来的数据一般是 id,所以传对象 id 是常用的)。
一对多中,设置外键属性的类(多的表)中,MySQL 中显示的字段名是:
外键属性名_id
。
返回值的数据类型是对象,书籍对象。
a. 获取出版社对象的 id
b. 给书籍的关联出版社字段 pulish_id 传出版社对象的 id
app01/views.py 文件代码:
def
add_book
(
request
)
:
# 获取出版社对象
pub_obj
=
models.
Publish
.
objects
.
filter
(
pk
=
1
)
.
first
(
)
# 获取出版社对象的id
pk
=
pub_obj.
pk
# 给书籍的关联出版社字段 publish_id 传出版社对象的id
book
=
models.
Book
.
objects
.
create
(
title
=
"冲灵剑法"
,
price
=
100
,
pub_date
=
"2004-04-04"
,
publish_id
=
pk
)
print
(
book
,
type
(
book
)
)
return
HttpResponse
(
book
)
多对多(ManyToManyField):在第三张关系表中新增数据
方式一:
传对象形式,无返回值。
a. 获取作者对象
b. 获取书籍对象
c. 给书籍对象的 authors 属性用 add 方法传作者对象
app01/views.py 文件代码:
def
add_book
(
request
)
:
# 获取作者对象
chong
=
models.
Author
.
objects
.
filter
(
name
=
"令狐冲"
)
.
first
(
)
ying
=
models.
Author
.
objects
.
filter
(
name
=
"任盈盈"
)
.
first
(
)
# 获取书籍对象
book
=
models.
Book
.
objects
.
filter
(
title
=
"菜鸟教程"
)
.
first
(
)
# 给书籍对象的 authors 属性用 add 方法传作者对象
book.
authors
.
add
(
chong
,
ying
)
return
HttpResponse
(
book
)
方式二:
传对象id形式,无返回值。
a. 获取作者对象的 id
b. 获取书籍对象
c. 给书籍对象的 authors 属性用 add 方法传作者对象的 id
app01/views.py 文件代码:
def
add_book
(
request
)
:
# 获取作者对象
chong
=
models.
Author
.
objects
.
filter
(
name
=
"令狐冲"
)
.
first
(
)
# 获取作者对象的id
pk
=
chong.
pk
# 获取书籍对象
book
=
models.
Book
.
objects
.
filter
(
title
=
"冲灵剑法"
)
.
first
(
)
# 给书籍对象的 authors 属性用 add 方法传作者对象的id
book.
authors
.
add
(
pk
)
关联管理器(对象调用)
多对多(双向均有关联管理器)
一对多(只有多的那个类的对象有关联管理器,即反向才有)
语法格式:
正向:属性名
反向:小写类名加 _set
注意:
一对多只能反向
常用方法:
add()
:用于多对多,把指定的模型对象添加到关联对象集(关系表)中。
注意:
add() 在一对多(即外键)中,只能传对象( *QuerySet数据类型),不能传 id(*[id表])。
*[ ]
的使用:
# 方式一:传对象
book_obj
=
models.
Book
.
objects
.
get
(
id
=
10
)
author_list
=
models.
Author
.
objects
.
filter
(
id__gt
=
2
)
book_obj.
authors
.
add
(
*author_list
)
# 将 id 大于2的作者对象添加到这本书的作者集合中
# 方式二:传对象 id
book_obj.
authors
.
add
(
*
[
1
,
3
]
)
# 将 id=1 和 id=3 的作者对象添加到这本书的作者集合中
return
HttpResponse
(
"ok"
)
反向:
小写表名_set
ying
=
models.
Author
.
objects
.
filter
(
name
=
"任盈盈"
)
.
first
(
)
book
=
models.
Book
.
objects
.
filter
(
title
=
"冲灵剑法"
)
.
first
(
)
ying.
book_set
.
add
(
book
)
return
HttpResponse
(
"ok"
)
create()
:创建一个新的对象,并同时将它添加到关联对象集之中。
返回新创建的对象。
pub
=
models.
Publish
.
objects
.
filter
(
name
=
"明教出版社"
)
.
first
(
)
wo
=
models.
Author
.
objects
.
filter
(
name
=
"任我行"
)
.
first
(
)
book
=
wo.
book_set
.
create
(
title
=
"吸星大法"
,
price
=
300
,
pub_date
=
"1999-9-19"
,
publish
=
pub
)
print
(
book
,
type
(
book
)
)
return
HttpResponse
(
"ok"
)
remove()
:从关联对象集中移除执行的模型对象。
对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在,无返回值。
author_obj
=
models.
Author
.
objects
.
get
(
id
=
1
)
book_obj
=
models.
Book
.
objects
.
get
(
id
=
11
)
author_obj.
book_set
.
remove
(
book_obj
)
return
HttpResponse
(
"ok"
)
clear()
:从关联对象集中移除一切对象,删除关联,不会删除对象。
对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在。
无返回值。
# 清空独孤九剑关联的所有作者
book
=
models.
Book
.
objects
.
filter
(
title
=
"菜鸟教程"
)
.
first
(
)
book.
authors
.
clear
(
)
ORM 查询
基于对象的跨表查询。
正向:属性名称
反向:小写类名_set
查询主键为 1 的书籍的出版社所在的城市(正向)。
book
=
models.
Book
.
objects
.
filter
(
pk
=
10
)
.
first
(
)
res
=
book.
publish
.
city
print
(
res
,
type
(
res
)
)
return
HttpResponse
(
"ok"
)
pub.book_set.all()
:取出书籍表的所有书籍对象,在一个 QuerySet 里,遍历取出一个个书籍对象。
pub
=
models.
Publish
.
objects
.
filter
(
name
=
"明教出版社"
)
.
first
(
)
res
=
pub.
book_set
.
all
(
)
for
i
in
res:
print
(
i.
title
)
return
HttpResponse
(
"ok"
)
正向:对象.属性 (author.au_detail) 可以跳转到关联的表(作者详情表)
author
=
models.
Author
.
objects
.
filter
(
name
=
"令狐冲"
)
.
first
(
)
res
=
author.
au_detail
.
tel
print
(
res
,
type
(
res
)
)
return
HttpResponse
(
"ok"
)
查询所有住址在黑木崖的作者的姓名(反向)。
一对一的反向,用
对象.小写类名
即可,不用加 _set。
反向:对象.小写类名(addr.author)可以跳转到关联的表(作者表)。
addr
=
models.
AuthorDetail
.
objects
.
filter
(
addr
=
"黑木崖"
)
.
first
(
)
res
=
addr.
author
.
name
print
(
res
,
type
(
res
)
)
return
HttpResponse
(
"ok"
)
菜鸟教程所有作者的名字以及手机号(正向)。
正向:
对象.属性(book.authors)
可以跳转到关联的表(作者表)。
作者表里没有作者电话,因此再次通过
对象.属性(i.au_detail)
跳转到关联的表(作者详情表)。
book
=
models.
Book
.
objects
.
filter
(
title
=
"菜鸟教程"
)
.
first
(
)
res
=
book.
authors
.
all
(
)
for
i
in
res:
print
(
i.
name
,
i.
au_detail
.
tel
)
return
HttpResponse
(
"ok"
)
查询任我行出过的所有书籍的名字(反向)。
author
=
models.
Author
.
objects
.
filter
(
name
=
"任我行"
)
.
first
(
)
res
=
author.
book_set
.
all
(
)
for
i
in
res:
print
(
i.
title
)
return
HttpResponse
(
"ok"
)
基于双下划线的跨表查询
正向:属性名称__跨表的属性名称
反向:小写类名__跨表的属性名称
查询菜鸟出版社出版过的所有书籍的名字与价格。
实例
res
=
models.
Book
.
objects
.
filter
(
publish__name
=
"菜鸟出版社"
)
.
values_list
(
"title"
,
"price"
)
反向:通过 小
写类名__跨表的属性名称(book__title,book__price)
跨表获取数据。
实例
res
=
models.
Publish
.
objects
.
filter
(
name
=
"菜鸟出版社"
)
.
values_list
(
"book__title"
,
"book__price"
)
return
HttpResponse
(
"ok"
)
查询任我行出过的所有书籍的名字。
正向:通过 属性名称__跨表的属性名称(authors__name) 跨表获取数据:
res = models.Book.objects.filter(authors__name="任我行").values_list("title")
反向:通过 小写类名__跨表的属性名称(book__title) 跨表获取数据:
res = models.Author.objects.filter(name="任我行").values_list("book__title")
查询任我行的手机号。
正向:通过
属性名称__跨表的属性名称(au_detail__tel)
跨表获取数据。
res = models.Author.objects.filter(name="任我行").values_list("au_detail__tel")
反向:通过
小写类名__跨表的属性名称(author__name)
跨表获取数据。
res = models.AuthorDetail.objects.filter(author__name="任我行").values_list("tel")