Django models多表操作

多表操作

单独创建第三张表的情况

推荐使用的是使用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的反向操作

    """
    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创建

```python
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)
posted @ 2017-07-10 22:20  hzxPeter  阅读(2291)  评论(1编辑  收藏  举报