Django 外键和表关系

外键

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
2
3
4
5
class Comment(models.Model):
content = models.TextField()
origin_comment = models.ForeignKey('self',on_delete=models.CASCADE,null=True)
# 或者
# models.ForeignKey('Comment',on_delete=models.CASCADE,null=True)
外键删除操作

如果一个模型使用了外键,那么在对方那个模型被删除后,该进行什么样的操作。可以通过on_delete来指定,可以指定的类型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# urls.py
from django.urls import path
from book import views

urlpatterns = [
# path('',views.index),
path('delete/',views.delete_view)
]
# views.py
def delete_view(request):
category = Category.objects.get(pk=1)
category.delete()
return HttpResponse("delete success!")
  • CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
  • PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。
  • SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
  • SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
  • SET():如果外键的那条数据被删除了。那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。
  • DO_NOTHING:不采取任何行为。一切全看数据库级别的约束。

表关系

表之间的关系都是通过外键来进行关联的,包括三种关系:一对一、一对多(多对一)、多对多等。

一对多
  • 应用场景:比如文章和作者之间的关系,一个文章只能由一个作者编写,但是一个作者可以写多篇文章。这种就是典型的一对多关系。
  • 实现方式:一对多或者多对一,都是通过ForeignKey来实现的。
1
2
3
4
5
6
7
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)
class Article(models.Model):
title = models.CahrField(max_length=100)
content = models.TextField()
author = models.ForeignKey("User",on_delete=models.CASCADE)

那么以后在给Article对象指定author就可以使用以下代码来完成

1
2
3
4
5
6
article = Article(title='abc',content='123')
author = User(username='hahawa',password='123.com')
# 要先保存到数据库中
author.save()
article.author = author
article.save()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def one_to_many_view(request):
# 1.一对多
# article = Article(title='钢铁是怎样炼成的',content='just do it')
# category = Category.objects.first()
# author = frontUser.objects.first()
# article.category = category
# article.author= author
# article.save()
# 2.获取某个分类下所有稳赚
# category = Category.objects.first()
# articles = category.article_set.all()
# for i in articles:
# print(i)
# 3.添加数据,bulk
category = Category.objects.first()
article = Article(title='111',content='222')
article.author = frontUser.objects.first()
category.article_set.add(article,bulk=False)
一对一
  • 应用场景:比如一个用户表和一个用户信息表。如果把所有信息都存放到一张表中可能会影响查询效率,因此可以把用户的一些不常用的信息存放到另外一张表中我们叫做UserExtension。但是用户表User和用户信息表UserExtension就是典型的一对一了。
  • 实现方式:Django为一对一提供了一个专门的Field叫做OneToOneField来实现一对一操作。
1
2
3
4
5
6
7
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)
class UserExtension(models.Model):
birthday = models.DateTimeField(null=True)
school = models.CharField(blank=True,max_length=50)
user = models.OneToOneField("User", on_delete=models.CASCADE)

在UserExtension模型上增加了一个一对一的关系映射。其实底层是在UserExtension这个表上增加了一个user_id,来和user表进行关联,并且这个外键数据在表中必须是唯一的,来保证一对一。

多对多
  • 应用场景:比如文章和标签的关系。一篇文章可以有多个标签,一个标签可以被多个文章所引用。因此标签和文章的关系是典型的多对多的关系。
  • 实现方式:Django为这种多对多的实现提供了专门的Field。叫做ManyToManyField。
1
2
3
4
5
6
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
tags = models.ManyToManyField("Tag",related_name="articles")
class Tag(models.Model):
name = models.CharField(max_length=50)

在数据库层面,实际上Django是为这种多对多的关系建立了一个中间表。这个中间表分别定义了两个外键,引用到article和tag两张表的主键。

-------------本文结束感谢您的阅读-------------
原创技术分享,感谢您的支持。