Django models多表操作

时间:2021-10-07 19:18:53

title: Django models多表操作
tags: Django
---

多表操作

单独创建第三张表的情况

推荐使用的是使用values/value_list,selet_related的方式,查询效率高

建立表

class Boy(models.Model):
    name = models.CharField(max_length=32)


class Girl(models.Model):
    nick = models.CharField(max_length=32)


class Love(models.Model):
    b = models.ForeignKey('Boy')
    g = models.ForeignKey('Girl')

表建立联合唯一索引unique_together

class Love(models.Model):
    b = models.ForeignKey('Boy')
    g = models.ForeignKey('Girl')

    # 建立联合唯一索引
    class Meta:
        unique_together = [
            ('b','g')
        ]
    """
 通过第三张表查与男生表有关系的女生
 下面是通过男生表反向查询 使用小写的表明love_set
 """
    # obj = models.Boy.objects.filter(name='钢弹').first() # 这里是对象
    # love_list = obj.love_set.all()
    # for item in love_list:
    # print(item.g.nick)

    """
 通过第三张表正向操作
 """
    # love_list = models.Love.objects.filter(b__name='钢弹')
    # for item in love_list:
    # print(item.g.nick)

    """
 但是上面的情况是for循环多次查询,效率低,
 用values,value_list进行优化,
 values获得是字典,value_list获取的是元组
 """
    # love_list = models.Love.objects.filter(b__name='钢弹').values('g__nick') # 仅查询一次
    # print(love_list) # <QuerySet [{'g__nick': '翠花'}, {'g__nick': '英子'}, {'g__nick': '妞子'}]>
    # for item in love_list:
    # print(item['g__nick']) # 这是取字典内容

    # love_list = models.Love.objects.filter(b__name='钢弹').values_list('g__nick')
    # print(love_list)
    # for item in love_list:
    # print(item[0]) # 取元组中的内容 取第一个

    """
 使用select_related 进行优化 查询到的是一个对象
 """
    # love_list = models.Love.objects.filter(b__name='钢弹').select_related('g') # 直接写外键原来的名字
    # print(love_list)
    # for obj in love_list:
    # print(obj.g.nick) # 是通过对象查

使用ManyToManyField 创建表

使用ManyToManyField,Django会自动生成第三张表,但是没有相应的类,是不能直接操作django自动生成的表的。但是可以通过Boy表关联的m间接的进行操作。

生成的第三张表示boy_m

class Boy(models.Model):
    name = models.CharField(max_length=32)
    m = models.ManyToManyField("Girl")  # 里面写的是要关联的表


class Girl(models.Model):
    nick = models.CharField(max_length=32)

对第三张表进行增删改

    obj = models.Boy.objects.filter(name='钢弹').first()
    print(obj.id,obj.name)
    
    """
 增加操作
 """
    # obj.m.add(2) # 增加一个 最终增加的是g_id--> 1 2
    # obj.m.add(1,2,3) # 增加多个
    # obj.m.add(*[4,]) # 使用列表进行接收

    """
 删除操作
 """
    # obj.m.remove(2) 
    # obj.m.remove(1,2,3) 
    # obj.m.remove(*[4,]) 

通过ManyToMany查询的,关键是通过all查询的是girl的对象

    obj = models.Boy.objects.filter(name='钢弹').first()
    print(obj.id,obj.name)
    girl_list = obj.m.all() # 查询的时候Django自动获得是girl对象
    print(girl_list)
    for item in girl_list:
        print(item.nick)  # 从对象获取

还可以继续进行过滤,filter内部的字段是Girl内部的

 girl_list = obj.m.all().filter(nick='翠花') # 查询的时候Django自动获得是girl对象
    for item in girl_list:
        print(item.nick)  # 从对象获取

修改内容

set是重置

obj.m.set([1,2])

清空clear是清空与之关联的全部

obj.m.clear()

ManyToMany的反向操作

`python """ ManyToMany的反向操作 小写的表名_set.all() 通过Girl取Boy """ obj = models.Girl.objects.filter(nick='翠花').first() boy_list = obj.boy_set.all() print(boy_list) for item in boy_list: print(item.name) # 从对象获取

混合使用

ManyToMany的缺陷是只能自动创建3列字段,不能再进行扩展。所以用到了下面的混合使用

不影响第三张表的使用,第三张表还是通过类进行增加删除

通过ManyToMany增加的是查询和清空的功能

创建

关键是 through through_fields,through指定的是自己创建的第三张表,

through_fields指定的是第三张表中的字段

这样就指定了自己创建第三张表,不通过ManyToMany创建

class Boy(models.Model):
    name = models.CharField(max_length=32)
    m = models.ManyToManyField("Girl",through='Love',through_fields=('b','g'))
    # m = models.ManyToManyField("Girl")


class Girl(models.Model):
    nick = models.CharField(max_length=32)


class Love(models.Model):
    b = models.ForeignKey('Boy')
    g = models.ForeignKey('Girl')

    # 建立联合唯一索引
    class Meta:
        unique_together = [
            ('b','g')
        ]

使用

obj.m.clear()
obj.m.all()

中间遇到的错误,强制删除了m表

ValueError: Cannot alter field app01.Boy.m into app01.Boy.m - they are not compatible types (you cannot alter to or from M2M fields, or add o
r remove through= on M2M fields)