初识Django5

7.1 多对一关系

7.1.1 多对一关系是什么

Django使用django.db.models.ForeignKey定义多对一关系。

ForeignKey需要一个位置参数:与该模型关联的类

class Info(models.Model):
      user = models.ForeignKey(other_model,on_delete=models.SET_NULL)

生活中的多对一关系:班主任,班级关系。一个班主任可以带很多班级,但是每个班级只能有一个班主任

class Headmaster(models.Model):
    name = models.CharField(max_length=50)
    def __str__(self):
        return self.name
class Class(models.Model):
    class_name = models.CharField(max_length=50)
    teacher = models.ForeignKey(Headmaster,null=True,on_delete=models.SET_NULL)
    def __str__(self):
        return self.class_name
7.1.2 多对一关系的增删改操作
>>> H1 = Headmaster(name='渔夫')
>>> H1.save()
>>> H1
>>> <Headmaster: 渔夫>
>>> H2 = Headmaster(name='农夫')
>>> H2.save()
>>> Headmaster.objects.all()
>>> [<Headmaster: 渔夫>, <Headmaster: 农夫>]

以上创建了两条老师数据
由于我们设置外键关联可以为空null=True,所以此时在班级表创建时,可以直接保存,不需要提供老师数据

>>> C1 = Class(class_name='一班')
>>> C2 = Class(class_name='二班')
# 如果外键设置不为空时,保存会引发以下错误
# IntegrityError: NOT NULL constraint failed: bbs_class.teacher_id
>>> C1.teacher = H1
>>> C2.teacher = H2
>>> C1.save()
>>> C2.save()

由于我们这是一个多对一的关系,也就说明我们的老师可以对应多个班级

  • 我们可以继续给H1老师分配新的班级
>>> C3 = Class(class_name='三班')
>>> C3.teacher = H1
>>> C3.save()
>>> H1.class_set.all()
[<Class: 一班>, <Class: 三班>]

一个班级只能对应一个老师,外键是唯一的,那么你在继续给C1班级分配一个新的老师时,会覆盖之前的老师信息,并不会保存一个新的老师

>>> H3 = Headmaster(name='伙夫')
>>> H3.save()
>>> C1.teacher
<Headmaster: 渔夫>
>>> C1.teacher=H3
>>> C1.save()
>>> C1.teacher
<Headmaster: 伙夫>
  • 把这个班级的老师删除,由于设置了外键字段可以为null,此时班级的老师选项为null
>>> t1 = Headmaster.objects.all().first()
>>> t1
>>> c1 = Class.objects.all().first()
<Headmaster: 渔夫>
>>> c1
<Class: 一班>
>>> c1.teacher
<Headmaster: 渔夫>
>>> t1.delete()
(1, {'modelsapp.Headmaster': 1})
>>> c1 = Class.objects.all().first()
>>> c1
<Class: 一班>
>>> c1.teacher
>>> #这里什么都没有,因为此时C1的老师已经是个None了
  • 注意:要记得删除之后要重新获取一次数据,否则查看到的结果中还是之前获取到的有老师的班级数据
7.1.3 多对一的正向查询

将老师分配个班级之后,由于班级表关联了老师字段,我们可以通过班级找到对应老师
虽然老师表中没有关联班级字段,但是也可以通过老师找到他所带的班级,这种查询方式也叫作关联查询

c1_teacher = C1.teacher
7.1.4 多对一的反向查询

通过模型类名称后追加一个_set,来实现反向查询

>>> H1.class_set.all()
<QuerySet [<Class: 一班>]>

7.2 一对一关系

7.2.1 一对一关系是什么

模型类使用OneToOneField用来定义一对一关系;

比如当你拥有一个老师表时,紧接着你还需要一个教授表,那么教授表可能拥有老师表的一系列属性,那么你还不想把老师表中的字段直接复制到教授表那么可以通过OnToOneField来实现教授表继承老师表。

OneToOneField(to, on_delete, parent_link=False, options)
class Teacher(models.Model):
    name = models.CharField(max_length=50)
    age = models.CharField(max_length=50)
    def __str__(self):
        return self.name
class Professor(models.Model):
    teacher = models.OneToOneField(Teacher,primary_key=True,on_delete=models.CASCADE)
    big_project = models.CharField(max_length=50)
    def __str__(self):
        return self.teacher.name
7.2.2 一对一关系的增删改操作
>>> t1 = Teacher.objects.create(name='Jack',age='22')
>>> t2 = Teacher.objects.create(name='Bob',age='17')
>>> p1 = Professor.objects.create(teacher=t1,big_project='雾霾净化术')
>>> p1.teacher
<Teacher: Jack>
>>> p1.teacher = t2
>>> p1.save()

在上面的测试中,看似已经将p1对应的教授变成了Bob;但是在数据库中之前t1老师所对应的教授信息还存在,此时的赋值操作并不会覆盖掉教授他之前的教授数据,只是重新创建了一条。
正确的做法应该是将某一条数据的一对一关系通过delete关系先删除之后再重新赋予

7.2.3 一对一关系正向查询
# 正向查询:通过教授,查询对应的讲师信息
>>> p1.teacher
<Teacher: Bob>
7.2.4 一对一关系反向查询
# 反向查询:通过讲师,查询教授信息, 反向查询时,只需要 模型类 本身即可
t1.professor.name

7.3 多对多关系

7.3.1 什么是多对多关系

多对多关系在模型中使用ManyToManyField字段定义

多对多关系可以是具有关联,也可以是没有关联,所以不需要明确指定on_delete属性

生活中,多对多关系:一个音乐家可以隶属于多个乐队,一个乐队可以有多个音乐家

class Artist(models.Model):
    artist_name = models.CharField(max_length=50)
    def __str__(self):
        return self.artist_name
class Band(models.Model):
    band_name = models.CharField(max_length=50)
    artist = models.ManyToManyField(Artist)
    def __str__(self):
        return self.band_name
7.3.2 多对多关系为什么不需要on_delete属性
# 在多对多的情况,有专门的第三张表,存储 对应关系, 表本身并没有字段来存储对应关系,此时删除任意数据,不影响另一张表数据
7.3.3 多对多关系的外键添加操作

创建音乐家以及乐队

>>> from bbs.models import Artist,Band
>>> A1 = Artist.objects.create(artist_name='Jack')
>>> A2 = Artist.objects.create(artist_name='Bob')
>>> B1 = Band.objects.create(band_name='FiveMonthDay')
>>> B2 = Band.objects.create(band_name='SHE')

创建出两个乐队之后对其进行音乐家的添加
多对多字段添加时,可以使用add函数进行多值增加

>>> B1.artist.add(A1,A2)
>>> B2.artist.add(A2)

B1乐队含有A1A2两名成员
B2乐队含有A1成员

>>> B1.artist.all()
[<Artist: Bob>, <Artist: Jack>]
>>> B2.artist.all()    
[<Artist: Jack>]
7.3.4 多对多关系的外键移除操作

多对多关联字段的删除,要使用remove来进行关系的断开
而不是直接使用deleteremove只会断开数据之间的联系,但是不会将数据删除

在B1乐队中删除A1乐家

>>> B1.artist.remove(A1)
>>> B1.artist.all()
<QuerySet [<Artist: Bob>]>
7.3.5 多对多关系的修改和查询
# 通过外键查询该乐队的全部音乐家
>>> B1.artist.all()
<QuerySet [<Artist: Bob>]>


# 反向查询:通过音乐家,查询该音乐家加入的乐队信息
A1.band_set.all()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值