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)
