当前位置: 首页 > 后端技术 > Python

DjangoNote7ManyToMany和OneToOne介绍

时间:2023-03-26 01:18:53 Python

ManyToMany是一种多对多的关系,在用途和用法上类似于外键ForeignKey。以下是本篇笔记目录:ManyToMany介绍通过参数through_fields参数ManyToMany关系数据增删改查OneToOne介绍1.ManyToMany介绍假设有两个模型,Person和Group,两个模型是many-对多关系。然后我们可以创建它的关系如下:#blog/models.pyclassPerson(models.Model):name=models.CharField(max_length=64)classGroup(models.Model):name=models.CharField(max_length=64)members=models.ManyToManyField(Person)通过上面的代码,我们创建了两个多对多关系的模型。我们执行完migrate操作后(可以不先执行,后面会改),系统除了创建Person两张表外,还会创建一张表Group。表名为blog_group_members,因为放在Blog应用下,所以表名的前缀是blog,然后加上模型名的小写作为group,加上字段名members。这个第三方表会有两个字段,person_id和group_id,用来关联两个模型。通过将person_id和group_id的数据写入到这个第三方表中,我们将这两个模型关联起来。获取他们对应关系的记录类似于ForeignKey的关系:根据Person数据查询关联的Group数据:person=Person.objects.get(id=1)group_list=person.group_set.all()#使用Group_set的小写加法根据Group数据查询关联的Person数据。这个查询方式略有不同,使用Group定义的members字段:group=Group.objects.get(id=1)person=group.members.all()#也可以根据条件搜索personperson=group.members.filter(name='hunter')2.在through参数上面的ManyToMany的定义中,我们没有添加任何参数,所以自动创建的表名是默认的,字段就是主键id两个模型。而如果我们有一些额外的需求,比如在添加Person和Group的关联关系时,需要添加关联时间,或者当我们要指定表名或模型名时,可以指定模型通过through属性。然后在其中添加我们需要的字段。比如我们要创建Person和Group的多对多关系,指定model名称为Membership,添加额外的字段,比如添加时间,可以通过参数指定:classPerson(models.模型):name=models.CharField(max_length=50)classGroup(models.Model):name=models.CharField(max_length=128)members=models.ManyToManyField(Person,through='Membership',)classMembership(models.Model):人=模型。ForeignKey(Person,on_delete=models.CASCADE)group=models.ForeignKey(Group,on_delete=models.CASCADE)date_joined=models.DateField()3.through_fields参数在我们上面创建的Membership模型中,我们对应的many-to-many字段是person和group,所以系统会自动找到对应的多对多字段。如果第三方表中有多个相同的Person或Group字段,即Membership,需要通过through_fields参数指定多对多的字段:classPerson(models.Model):name=models.CharField(max_length=50)classGroup(models.Model):name=models.CharField(max_length=128)members=models.ManyToManyField(Person,through='Membership',through_fields=('group','person'),)类成员资格(models.Model):group=models.ForeignKey(Group,on_delete=models.CASCADE)person=models.ForeignKey(Person,on_delete=models.CASCADE)inviter=models.ForeignKey(Person,on_delete=models.CASCADE,related_name="membership_invites",)invite_reason=models.CharField(max_length=64)4.ManyToMany关系数据的增删改查接下来我们设置最终模型如下,演示ManyToMany的增删改查:类人(模型。模型):名称=模型。CharField(最大长度=50)类组(模型。模型):name=models.CharField(max_length=128)members=models.ManyToManyField(Person,through='Membership',)classMembership(models.Model):person=models.ForeignKey(Person,on_delete=models.CASCADE)组=models.ForeignKey(Group,on_delete=models.CASCADE)date_joined=models.DateField()invite_reason=models.CharField(max_length=64)现在我们有两个模型Person和Group,以及两个模型之间的关系表Membership。如果我们要创建对应关系,我们需要创建一个Membership实例创建记录先创建Person和Group:fromblog.modelsimportPerson,Group,Membershiphunter=Person.objects.create(name='hunter')group_1=Group.objects.create(name='group_1')创建多对-manyRecord:m1=Membership.objects.create(person=hunter,group=group_1,date_joined='2022-01-01',invite_reason='xxx')根据单个Person记录获取所有相关Group记录,使用方法同外键查找方法:groups=hunter.group_set.all()根据单个Group记录获取所有相关Person记录,基于多对多字段查找:persons=group_1.members.all()获取基于Membership关系记录的Person和Group记录,可以直接使用外键:m1.personm1.group根据Group添加多对多记录使用add:paul=Person.objects.create(name='pual')group_1.members.add(paul,through_defaults={'date_joined':'2022-01-01'})其中through_defaults参数是一个字典,内容是一个additional字段添加到多对多关系表中。使用create创建基于Group的多对多记录:如果没有对应的Person记录,可以直接创建group_1.members.create(name='mary',through_defaults={'date_joined':'2022-01-01'})使用set根据Group刷新多对多记录:使用set方法设置多对多关系:jack=Person.objects.create(name='jack')lucy=Person.objects.create(name='lucy')group_1.members.set([jack,lucy],through_defaults={'date_joined':'2022-01-01'})需要注意的是,使用set()方法后添加关联,之前设置的Group实例的所有关联数据都会被清空。也就是说,set()中的关联数据集就是最终的关联数据。使用remove根据Group删除一条多对多的记录:上面我们使用set()方法设置了jack和lucy两个相关数据,现在我们要删除jack-group_1关系,可以使用remove()方法:group_1.members.remove(jack)使用clear清除一个Group实例上的所有关系:group_1.members.clear()多对多搜索:根据Person的条件搜索Group数据:例如namefieldofthesearchPersonisGroupdataof'hunter'Group.objects.filter(members__name='hunter')根据Group条件搜索Person数据:例如搜索Group的name字段为'group_1'的Person关联数据:Person.objects.filter(group__name='group_1')如果要搜索额外的关联字段:Person.objects.filter(group__name='group_1',membership__date_joined='2022-01-01')5.OneToOne引入了一个不同于多对一和多对多的关系,OneToOne是一对一的关系,也就是说一个of数据只能与另一条数据相关联。下面是OneToOne对应的两个模型:classPlace(models.Model):name=models.CharField(max_length=50)address=models.CharField(max_length=80)def__str__(self):return"%stheplace"%self.nameclassRestaurant(models.Model):place=models.OneToOneField(Place,on_delete=models.CASCADE,default=None,related_name='place_restaurant',null=True)接下来创建两条数据:r_1=Restaurant.objects.create()p_1=Place.objects.create(name='beijing',address='beijing')根据Restaurant获取Place数据,直接根据字段获取数据:r_1.place如果获取Restaurant数据根据Place,因为是OneToOne关系,所以可以直接获取:上面模型中,我们定义了related_name,所以是:p_1.place_restaurant如果没有定义related_name和related_query_name,那么就是小写的model:p_1.restaurant但是从Place到Restaurant获取数据,如果没有这种OneToOne对应关系,比如我们上面直接创建的p_1,如果用这种方式获取关联数据会报错,因为没有这种OneToOne数据。那么这个时候我们可以先判断是否有对应的OneToOne数据:hasattr(p_1,'place_restaurant')#返回布尔数据#或者getattr(p_1,'place_restaurant',None)以上就是这个笔记的全部内容接下来,我们将介绍Meta在模型中的使用。