Django models多表操作

时间:2025-01-16 10:37:27

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的反向操作

    """
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)