汇总对比理解Django数据库模型表关联的三种方法:OneToOneFiled()【一对一】、ForeignKey【一对多】、ManyToManyField()【多对多】
在理解本篇博文前建议大家先看一看我之前写的博文:https://blog.youkuaiyun.com/wenhao_ir/article/details/131542371从这篇博文可以对关联的整个具体的过程有个具体的了解。
在数据表进行关联操作时,Django提供了三种关联操作,即:
①使用方法 models.OneToOneField()实现一对一的关联;
②使用方法 models.ForeignKey()实现一对多的关联;
③使用方法 models.ManyToManyField()实现多对多的关联。
00-基本假设
为了理解这三种关系,假设有下面的两个模型和四条数据。
两个模型:
Author 和 Post
四条数据:
author1 | post1 |
---|---|
author2 | post2 |
01-OneToOneFiled()【一对一】的理解
对于一对一的关联,很好理解,就是一张表中的某条数据只能与另一张表中的某条数据相关联。
示例如下:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
# Other fields of the Author model
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# Other fields of the Post model
author = models.OneToOneField(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
在上述示例中,通过在Post中使用方法OneToOneField(),使每篇帖子都与一个作者关联。
由于是一对于的关联,所以如果 post1 关联了 author1,那么author1就不能与post2关联了。
如果此时想要让post1 关联 post2,那么可以像下面这样做:
# 解除author1与post1的关联
author1.post.delete()
# 建立author1与post2的新关联
post2 = Post(title='Another Post', content='This is another post.', author=author1)
post2.save()
同样,换一个方向来看,一旦post1与author1关联后,那么post1也不能与author2关联了。 如下图所示:
如果需要将post1
与author2
关联,需要先解除post1
与author1
的关联,然后再与author2
建立新的关联。以下是解除关联的示例代码:
# 解除post1与author1的关联
post1.author = None
post1.save()
# 建立post1与author2的新关联
post1.author = author2
post1.save()
通过将post1.author
设置为None
,我们可以解除post1
与author1
的关联。然后,我们可以将post1.author
设置为author2
,从而与author2
建立新的关联。
02-ForeignKey【一对多】的理解
对于ForeignKey【一对多】的详细操作过程,我已经在博文https://blog.youkuaiyun.com/wenhao_ir/article/details/131542371中写得很清楚了。
这里重点解释什么叫“一对多”。
示例代码如下:
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
在上面的代码情况下,模型Post通过方法ForeignKey()关联到模型Author,Post为“一对多”中的“多”,Author为一对多”中的“一”。
在ForeignKey方法的情况下,即一对多的情况下,当post1、post2与author1关联后,就不能再与author2关联了。 如下图所示:
上面的红线表示post1、post2与author1关联,一旦post1、post2与author1关联后,就不能再与author2关联了。所以上面的两条蓝色的线我都打了叉。
也就是说一个post一旦与某个author关联,那么它就不能再与别的author关联了,但是相应的author还能与别的post关联。这就是谓的一对多的关系。
03-ManyToManyField()【多对多】的理解
示例代码如下:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
# Other fields of the Author model
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
authors = models.ManyToManyField(Author)
# Other fields of the Post model
def __str__(self):
return self.title
在上面的两个模型中,通过下面这条语句将两个模型进行多对多的关联:
authors = models.ManyToManyField(Author)
在这种情况下,post1与author1关联后,仍可以与author2关联,即post的author可以有多个,比如这里的post1的author可以为author1与author2。
而多个post也可以与同一个author关联,即一个author可以有多个post。比如这里的post1与author1关联后,post2也还可以与author2关联,这样就实现了author1有post1和post2,即一个author可以有多个post。
通过上面的关联,就实现了一篇post可以有多个author,而一个author也可以有多个post。这就是所谓的多对多关系。如下图所示:
以下是示例代码,展示如何使用多对多关联:
# 创建两个Author对象
author1 = Author(name='John Doe')
author1.save()
author2 = Author(name='Jane Smith')
author2.save()
# 创建一个Post对象并将其与两个Author关联
post = Post(title='Hello World', content='This is my post.')
post.save()
post.authors.add(author1, author2)
# 访问与Post关联的Author
print(post.authors.all()) # 输出:[<Author: John Doe>, <Author: Jane Smith>]
# 访问与Author关联的Post
print(author1.post_set.all()) # 输出:[<Post: Hello World>]
print(author2.post_set.all()) # 输出:[<Post: Hello World>]
在上面的示例中,我们创建了两个 Author
对象:author1
和 author2
。然后,我们创建了一个 Post
对象 post
,并通过 post.authors.add()
将其与两个 Author
对象关联。
通过 post.authors.all()
,我们可以访问与 post
相关联的所有 Author
对象。
同时,我们也可以通过 author1.post_set.all()
和 author2.post_set.all()
访问与 author1
和 author2
相关联的所有 Post
对象。
如果是已经存在的数据库记录值,可以像下面这样操作:
如果post1
和post2
已经是现有记录,你可以使用get
方法从数据库中获取它们,然后将它们与已存在的Author
关联。以下是具体步骤:
假设post1
和post2
是已存在的Post
记录:
# 获取已存在的 Post 记录
post1 = Post.objects.get(title="已存在的标题1")
post2 = Post.objects.get(title="已存在的标题2")
# 获取已存在的 Author 记录
existing_author = Author.objects.get(name="已存在的作者")
# 将 Author 与两个 Post 进行关联
existing_author.posts.add(post1, post2)
# 保存更改
existing_author.save()
在这个例子中,我们使用get
方法从数据库中获取post1
和post2
,然后使用add
方法将它们与existing_author
关联,最后调用save
方法保存更改。
确保你的查询条件足够唯一以确保正确获取现有的Author
、Post
记录。如果查询条件不唯一或无法找到记录,get
方法可能会引发DoesNotExist
或MultipleObjectsReturned
异常,因此需要适当处理这些情况。具体来说:
Author.objects.get(name="已存在的作者")
使用get
方法查询数据库,期望结果是唯一的,如果查询条件匹配多个记录,将引发MultipleObjectsReturned
异常。同样,如果没有找到匹配的记录,将引发DoesNotExist
异常。
因此,在实际应用中,应该根据具体情况进行适当的异常处理。你可以使用try
和except
块来捕获这些异常,并处理它们,例如:
try:
existing_author = Author.objects.get(name="已存在的作者")
except Author.DoesNotExist:
print("未找到匹配的作者记录")
except Author.MultipleObjectsReturned:
print("存在多个匹配的作者记录")
在这个例子中,我们分别捕获了DoesNotExist
和MultipleObjectsReturned
异常,并打印了相应的信息。你可以根据实际需求进行适当的处理,例如选择一个默认的作者记录,提示用户选择,或者采取其他合适的措施。
04-“多对多关联”在操作上与“一对一”、“多对一”的重要区别
从上面的多对多关联的操作上我们可以看出,“多对多关联”是在模型对象创建好后,再进行关联操作,而“一对一”、“多对一”的关联操作都是在在模型对象创建时就指定关联关系。