外键
mysql中常见2种引擎,一种是InnoDB,另外一个是MyIsam。InnoDB引擎是支持外键约束的,外键的存在使得ORM框架在处理表关系的时候异常的强大。
类定义为class Foreignkey(to,on_delete,**options)
- 第一个参数是引用的哪个模型
- 第二个参数是在使用外键引用的模型数据被删除了,这个字段如何处理。比如有CASCADE(默认的选项,级联删除)、SET_NULL(置空模式,删除的时候,外键字段被设置为空)等。
1
2
3
4
5
6
7
8
9
10
11
12# models.py
# User模型在user这个app中
calss User(models.Model):
username = models.CharField(max_length=20)
password = models.CahrField(max_length=200)
# Article模型在article这个app中
class Article(model.Molde):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey("user.User",on_delete=models.CASCADE)
# category = models.ForeignKey("User",on_delete=models.CASCADE,null=True)
# 如果外键是在其他app上,写法是:app.模型名
如果模型的外键引用的是本身自己这个模型,那么to参数可以为self,或者是这个模型的名字。在论坛开发中,定义模型就需要使用外键来引用自身。
1 | class Comment(models.Model): |
外键删除操作
如果一个模型使用了外键,那么在对方那个模型被删除后,该进行什么样的操作。可以通过on_delete来指定,可以指定的类型如下:
1 | # urls.py |
- CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
- PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。
- SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
- SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
- SET():如果外键的那条数据被删除了。那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。
- DO_NOTHING:不采取任何行为。一切全看数据库级别的约束。
表关系
表之间的关系都是通过外键来进行关联的,包括三种关系:一对一、一对多(多对一)、多对多等。
一对多
- 应用场景:比如文章和作者之间的关系,一个文章只能由一个作者编写,但是一个作者可以写多篇文章。这种就是典型的一对多关系。
- 实现方式:一对多或者多对一,都是通过ForeignKey来实现的。
1 | class User(models.Model): |
那么以后在给Article对象指定author就可以使用以下代码来完成
1 | article = Article(title='abc',content='123') |
1 | def one_to_many_view(request): |
一对一
- 应用场景:比如一个用户表和一个用户信息表。如果把所有信息都存放到一张表中可能会影响查询效率,因此可以把用户的一些不常用的信息存放到另外一张表中我们叫做UserExtension。但是用户表User和用户信息表UserExtension就是典型的一对一了。
- 实现方式:Django为一对一提供了一个专门的Field叫做OneToOneField来实现一对一操作。
1 | class User(models.Model): |
在UserExtension模型上增加了一个一对一的关系映射。其实底层是在UserExtension这个表上增加了一个user_id,来和user表进行关联,并且这个外键数据在表中必须是唯一的,来保证一对一。
多对多
- 应用场景:比如文章和标签的关系。一篇文章可以有多个标签,一个标签可以被多个文章所引用。因此标签和文章的关系是典型的多对多的关系。
- 实现方式:Django为这种多对多的实现提供了专门的Field。叫做ManyToManyField。
1 | class Article(models.Model): |
在数据库层面,实际上Django是为这种多对多的关系建立了一个中间表。这个中间表分别定义了两个外键,引用到article和tag两张表的主键。