前几篇文章在记录ForeignKey时,其实已经实现一对多的关系,这篇文章来详细记录下。
应用场景:
文章和作者的关系。一篇文章只能有一个作者,但是一个作者可以有多篇文章。文章和作者的关系就是典型的多对一的关系。
实现一对多关系就是通过 ForeignKey来实现:
1、首先通过ForeignKey来关联User表中的数据(下边案例我们关联的是id为1的数据,一个user用户(可以把user理解为一个作者)可以对应多篇文章);
2、第一次关联完之后,第二次我们想再次关联User表中id为1的数据时,应该:把User表中id为1的数据先取出来,然后再次关联,详细代码如下;
# 模型
class User(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
class Meta:
db_table = 'User'
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey('User', on_delete=models.CASCADE)
class Meta:
db_table = 'Article'
def index(res):
# 第一次关联
user = User(username='lxc', password='123456')
user.save()
article = Article(title='测试标题', content='测试内容')
article.author = user
article.save()
return 'success'
def index(res):
# 第二次关联,直接把User表中 id为1的数据取出,然后再次关联
user = User.objects.get(pk=1)
article = Article(title='测试1', content='测试内容1')
article.author = user
article.save()
return 'success'
效果如下:
这样就形成一个一对多的关系(User表中id为1的数据,关联了2篇文章)。
获取一个作者下的所有的文章:
小编目前已知的有三种方式:
1、方法一
以上边案例为例,取出User表中id为1对应的所有文章数据,使用filter 过滤出author字段为User表中的id为1的数据,有点绕,但是也很好理解,User表中的id为1的作者对应在Article表中有2条数据:
from apps.test_three.models import User, Article
def index(res):
article = Article.objects.filter(author=User.objects.get(pk=1))
print(article)
return 'success'
2、方法二
使用外键的表名_set 属性
这里有个小知识点,先看完代码:
def index(res):
user = User.objects.get(pk=1)
all_articles = user.article_set.all()
print(all_articles)
# <QuerySet [<Article: Article object (1)>, <Article: Article object (3)>]>
render(res, 'test_html.html')
在django中,如果这个模型被其它模型使用外键的方式引用,那么django会自动给这个模型添加一个属性,这个属性的名字为:引用的模型名称小写形式_set 。上边Article模型引用了User模型,所以User模型会被django添加一个属性为:article_set,返回的也是一个QuerySet,也可使用all方法获取全部文章,或者使用first获取第一篇文章。
3、方法三
如果以上两种方法都不和你胃口,还有第三种方式:
在引用字段的参数中,添加 related_name='自定义名称' 为关联名称的意思,添加完之后,如果想取User模型下的某个id对应的多篇文章,用法跟方法二一样,来体验下:
class User(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
class Meta:
db_table = 'User'
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey('User', on_delete=models.CASCADE, related_name='articles') # 指定为articles
class Meta:
db_table = 'Article'
把User表中id为1对应的文章数据全部取出来,效果与方法二一样:
def index(res):
user = User.objects.get(pk=1)
all_articles = user.articles.all() # 使用关联名称 articles来取数据
print(all_articles)
# <QuerySet [<Article: Article object (1)>, <Article: Article object (3)>]>
return render(res, 'test_html.html')
tips:
1、使用方法三 related_name 来自定义关联名称时,django将不在会自动给你生成一个 使用外键的表名_set 的属性了,代替它的是方法三中的自定义名称!!!