20221006django关系模型多对多多对一和一对一
一对一
举例:用户模型和用户扩展信息是属于一对一关系。一对一关系
在Django模型中是通过OneToOneField
类型来表示的。
类型用法:OneToOneField(to, on_delete, parent_link=False, **options)
;
- to 要进行关联的模型名称
- on_delete 删除关联表中数据时要执行的操作配置项
其实一对一关系
算是一种特殊的多对一关系
,只不过反向查询的时候返回的是一个单一对象
。
多对一
举例: 一个分类下有多个博客文章,是属于多对一关系。在Django模型中是通过 ForeignKey
类型来表示的。
类型用法:ForeignKey(to, on_delete, **options)
to 和 on_delete的含义和上面一对一关系一样
options 包含有:
- related_name
- related_query_name
- swappable
- db_constraint
- limit_choices_to
常用的是前两个,后面三个不常用,这里不做介绍,前两个的具体含义和用法详见后面扩展部分
多对多
举例:一个文章会有多个标签,每个标签下也会有多个文章。在Django模型中是通过 ManyToManyField
类型来表示的。
类型用法: ManyToManyField(to, **options)
只有 to 参数,没有 on_delete
options 包含有:
- related_name
- related_query_name
- symmetrical
- through
- through_fields
- db_table
- limit_choices_to
这里需要注意 through这个参数。默认情况下,ManyToManyField 在Django中会自动创建一个中间表,用常见的 博客应用来说明,中间表名称默认是 blog_post_tags
,该表有三个字段
- id 该表本身的递增字段
- post_id 关联到 Post模型的 id字段
- tag_id 关联到 Tag模型的 id 字段
如果不想使用默认的创建规则,则可以通过 through
参数指向一个自定义的中间模型。当然自定义中间模型的时候,如果中间表的字段没有使用默认规则,然后可以通过 through_fields
来指定,它是一个二元组
扩展
1、on_delete属性的取值说明
-
models.CASCADE
级联删除,也就是1的那头删除,对应的多的这头也删除,比如级联删除时:删除博客的分类,同时也会删除该分类下的所有博客文章 -
models.PROJECT
保护,在删除的时候会触发一个ProjectedError
来组织删除 -
models.RESTRICT
django3.1新增。正常情况下会触发一个RestrictedError
来阻止删除。但是如果该对象同时引用了其他对象,且是CASCADE
则可以被删除
官网案例:
模型如下,注意 Song 关联了 Album 且删除属性是RESTRICT
, 同时还关联了 Artist,删除属性是CASCADE
1 | class Artist(models.Model): |
则根据上面的定义描述,创建如下记录
1 | 'artist one') artist_one = Artist.objects.create(name= |
1、album_one/album_two 删除都会报 RestrictedError
,因为 song_one/song_two 都关联了Album,且是RESTRICT
2、artist_two 删除会报 RestrictedError
,因为 song_two 关联了album_two, album_two关联了 artise_two, song_two是 RESTRICT
限制,所以artist_two 删除会报 RestrictedError
3、artist_one 删除是正常的。但是请注意:
这个时候是只是删除了artist_one, 没有删除 album_one 和 song_one ,没有级联
删除
-
models.SET_NULL
删除时设置关联的字段为Null,但是需要该字段同时null=True
,一般也要配置blank=True
-
models.SET_DEFAULT
删除时设置关联的字段的默认值,但是需要该字段具备默认值才行 -
models.SET()
删除时设置关联的字段为给定的值,或者一个可调用对象的结果 。 -
models.DO_NOTHING
顾名思义,什么也不做
2、关于 related_name
和 related_query_name
举个例子来解释
1 | class Category(models.Model): |
1、related_name/related_query_name 是出现自多对一或者多对多的关系中
2、正常情况下,在 ForeignKey 或者 ManyToManyField 一侧,实际用法如下
- 查询某个分类下都有哪些文章的时候是
1 | c1 = Category.objects.get(pk=1) |
- 查询文章标题是什么或者包含什么的对应的分类的时候
1 | # 默认是使用的 model 小写名字 |
3、正常情况下不指定,Django给了合理的默认值。一般
- related_name 是相关对象的属性,比如 cs 是 c1 对象的属性
- related_query_name 是用于Django查询集合
官网参考地址 https://docs.djangoproject.com/en/3.2/ref/models/fields/#module-django.db.models.fields.related
20221006django关系模型多对多多对一和一对一
http://blog.colinspace.com/2022/10/06/20221006django关系模型多对多多对一和一对一/