通过一个实际例子说明Django中的数据库操作方法法ForeignKey()-外键的用法【数据表“一对多”关系】,并详解“中间关系表”、反向关系(related_name)、反向关系名冲突的概念

当使用Django进行数据库操作时,ForeignKey(外键)是一种非常有用的字段类型。它允许在数据库表之间创建关联关系,类似于其他数据库系统中的外键概念。通过ForeignKey字段,我们可以建立一个模型与另一个模型的一对多关系。

以下是一个实际例子,使用ForeignKey字段在Django中创建一对多关系,初学者可以通过这个实际例子去仔细观察数据表“一对多”关系是怎么一回事儿。

假设我们正在开发一个博客应用程序,其中有两个主要的模型:作者(Author)和文章(Post)。一个作者可以有多篇文章,而一篇文章只能由一个作者撰写。在这种情况下,我们可以使用ForeignKey字段将文章与作者关联起来。

首先,让我们创建Author模型和Post模型:

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()
    writer = models.ForeignKey(Author, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

在上述代码中,我们定义了Author模型和Post模型。Post模型中的writer字段是一个ForeignKey字段,它将Post模型与Author模型相关联。on_delete=models.CASCADE参数表示当关联的作者被删除时,与该作者关联的所有文章也将被删除。

接下来,我们可以使用这些模型创建数据库表:

python manage.py makemigrations
python manage.py migrate

现在我们已经创建了Author和Post表,我们用下面的代码来演示数据表“一对多”关系的操作及对数据表的影响。

import os
import django

# 设置Dango运行时需要的环境变量DJANGO_SETTINGS_MODULE
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myshop.settings')

# 加载Django的设置
django.setup()

# 导入模型
from app1.models import Author, Post

# 创建一个作者
author1 = Author(name='wenhao')
author1.save()

# 创建一篇文章,并将其与刚才创建的作者相关联
post1 = Post(title='First Post', content='Hello, World!', writer=author1)
post1.save()

# 再创建一篇文章,也将其与刚才创建的作者相关联
post2 = Post(title='My love', content='I love wang hong', writer=author1)
post2.save()

# 获取一个作者的所有文章
author_get = Author.objects.get(name='wenhao')
posts_all = author_get.post_set.all()
for post in posts_all:
    print(post)


在上面的代码中,作者“wenhao”发表了两篇文章,文章的title分别为’First Post’和’My love’,通过Post模型的一对多成员writer关联到表 Author。

如果要理解语句posts_all = author_get.post_set.all()中的post_set(),请参看我的另一篇博文,链接:https://blog.csdn.net/wenhao_ir/article/details/131668597

上面的代码运行结果如下:
在这里插入图片描述
可见作者“wenhao”对应的两篇文章的标题被打印出来了。
这里要多问一句,为什么内容没被打印出来呢?
请注意数据表模型中定义的下面语句:

    def __str__(self):
        return self.title

并结合Python的“魔术方法“(magic method)或“特殊方法“(special method)去理解这个问题,关于Python的“魔术方法“(magic method)或“特殊方法“(special method),请参见链接:https://blog.csdn.net/wenhao_ir/article/details/131395984

我们再去观察一下数据表中的内容,如下:
在这里插入图片描述

在这里插入图片描述

大家可以仔细观察下这两张表的内容,看下Author是怎样和Post进行一对多关联的。
从上面的数据库截图中可以看出,在表 app1_post中,外键字段的名字为 writer_id,而不是想像中的 writer,这一点要注意,其值就是作者wenhao在表app_author中的id字段。
显然,光凭数据表里的数据,是无法知道字段表 app1_post中的writer_id是指向表app_author中的数据,Django肯定在另外的地方记录下了这种对应关系,记录下这种对应关系的表叫“中间关系表”,这个“中间关系表”并没有在数据库中,目前昊虹君也不知道具体在哪里。不过在Django的某个地方,肯定存在着一个“中间关系表”,它的内容如下:
writer_set→Author
提问:_set 是怎么来的?
答:从writer映射到模型Author 的关系在数据库中叫做反向关系,writer_set称为反向关系名,即related_name,如果不指定反向关系名,统就会以"字段名_set"的格式作为其默认反向关系名。

显然,如果模型中,有多个“一对多”或“多对多”关系时,相应的字段名不能相同,否则会引起冲突。为什么?举个例子,假如另一个模型中也有一个一对多的关系,这个一对多的关系指向模型Book,但是这个一对多的关系的字段名也为writer,那么“中间关系表”中就会存在一条下面这样的反向关系记录:
writer_set→Book
所以,“中间关系表”的内容如下:

writer_set→Author
writer_set→Book

这样,通过中间关系表就无法分清楚到底是哪个writer与Author模型相对应,又是哪个writer与Book模型相对应。
如果不能避免字段名字的相同,就要使用相关名称参数(related_name)来为其在中间关系表中指定反向关系名,比如:

writer = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='blogs_writer')
writer = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='book_writer')

经上面的两条代码指定反向关系名,便没有冲突了。
并且用related_name参数指定反向关系名后,就可以用这个反向关系名来访问相应的字段了,比如下面这个示例:

# 获取一个作者的所有文章
author_get = Author.objects.get(name='wenhao')
posts_all = author_get.blogs_writer.all()
for post in posts_all:
    print(post)

运行上面的代码,可得到下面的结果:
在这里插入图片描述

在建立一对多关系或多对多关系时,建议大家指定不容易重复的反向关系名,这样可以提高代码的健壮性。

扩展阅读:
Django中使用反向关系名称(related_name)解决由“多对多”关系引起的字段名字冲突问题引起的迁移命令报错。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值