Django默认ORM(七):一对一(O2O)自关联操作
以相亲关系表举例,男女生信息表都放在一个数据表中,男生可以看到相亲过的女生,同理女生也可以看到相亲过的男生
1.前戏:通过外键表引出:
- 所有的信息都整合在一张表里,通过另一张按照自定义规则设置的外键表,实现连表操作查询的功能。 建立外键表: - 由于是对同一张表操作,django框架此时就没有那么智能,此时就需要我们自定义约束规则,以规范使用! PS:补充一点内容:ForeignKey()中的参数: - to="表名" - to_field="列名" #建立外键关系的列名,默认是id列 - related_query_name="自定义名" #定义一个反向操作的名称,保留了反向连表操作中_set的属性 - related_name="自定义名" #定义一个反向操作的名称,直接通过自定义名即可反向操作 related_query_name和related_name都是定义的反向操作的属性,一般常用于related_name. 举例说明:-外键表中,反向操作的名字,女生为a,男生为b! # related_query_name obj对象男.b_set.all() obj对象女.a_set.all() # related_name obj对象男.a.all() obj对象女.b.all() 1)models.py文件中,ORM利用类创建表的代码: #创建用户信息表 class Userinfo(models.Model): nickname = models.CharField(max_length=32) #昵称 username = models.CharField(max_length=32) #用户名 password = models.CharField(max_length=64) #密码 gender_choices = ( (1,"男"), (2,"女"), ) gender = models.IntegerField(choices=gender_choices) #性别 #外键关联表 class U2U(models.Model): g = models.ForeignKey("Userinfo",related_name="boys") #设置与女生关联的外键,及反向操作的名称 b = models.ForeignKey("Userinfo",related_name="girls")#设置与男生关联的外键,及反向操作的名称 2)给两张表添加数据: - 信息表就不用多说了,就是平常添加的顺序,此除多说说关联表,关联表添加数据的方式有两种: #第一种:知道ID直接添加: models.U2U.objects.create(b_id=1,g_id=4) #第二种:先从信息表中,获取相对应的对象,然后在关联表中直接添加这个对象,内部会做转换操作,拿取用户的id。 boy = models.Userinfo.objects.filter(gender=1,id=2).first() gril = models.Userinfo.objects.filter(gender=2,id=5).first() models.U2U.objects.create(b=boy,g=gril) 3)表和数据都有了,那就剩下操作了,怎么获取相对应的信息! - 此处再次普及一下正反向操作的定义: 正反向操作是以外键为标志,从当前有外键的表,通过外键获取对应表的数据操作称为正向操作;反之,从数据表反向获取关联表的操作,称为反向操作。 注意一点:不管是正反向操作,获取的对象(数据)都是跨表之后的另一张表的对象(信息)! root = models.Userinfo.objects.filter(id=1).first() #先获取一个信息表的对象 result = root.girls.all() #通过定义的反向关联的名字,反向查找与当前对象有关系的对象,注意:此处获取的是 U2U表的对象! for u in result: print(u.g.nickname) #通过拿到的对象,在通过外键关系,正向获取有关系对象的昵称。
2.正题:
- 既然上边的操作可以实现信息的整合,那么建立联系的外键是否也可以写在一张表里呢?答案是肯定的。这种创建关联的方式就叫做自关联。 本质:把所有的信息都在一张表上创建,虽然只有一张表,但是我们可以再想象着生成一张一模一样的表,这两个表之间通过外联建立关系。 虽然是叫做自关联,实质上还是两张表的操作! - M2M自关联特性:(多对多) #创建自关联的整合表 class Userinfo(models.Model): nickname = models.CharField(max_length=32) #昵称 username = models.CharField(max_length=32) #用户名 password = models.CharField(max_length=64) #密码 gender_choices = ( (1,"男"), (2,"女"), ) gender = models.IntegerField(choices=gender_choices) #性别 m = models.ManyToManyField('Userinfo') #ManyToManyField有一特性,就是会自动生成一张关系表,我们设置的这个自关联表中,会生成三列,id,from_userinfo_id,to_userinfo_id 自增id不用说,from_userinfo_id,to_userinfo_id,从列名上就能看出来,分别代表着userinfo表的不同id,一个是从哪儿来,一个是去哪里。 obj = models.Userinfo.objects.filter(id=1).first() # from_userinfo_id #正向操作 sql语句 obj.m => select xx from xx where from_userinfo_id = 1 # to_userinfo_id #反向操作 sql语句 obj.userinfo_set => select xx from xx where to_userinfo_id = 1 - 关系表内自定义规则:记住定义了规则之后,一定要严格遵守!!! 定义: # 前面列:男生ID # 后面列:女生ID 应用: # 男生对象 obj = models.UserInfo.objects.filter(id=1).first() # 根据男生ID=1查找关联的所有的女神 obj.m.all() # 女生 obj = models.UserInfo.objects.filter(id=4).first() # 根据女生ID=4查找关联的所有的男生 obj.userinfo_set.all()