Python - Django - ORM 多对多表结构的三种方式
多对多的三种方式:
- ORM 自动创建第三张表
- 自己创建第三张表, 利用外键分别关联作者和书,关联查询比较麻烦,因为没办法使用 ORM 提供的便利方法
- 自己创建第三张表,使用 ORM 的 ManyToManyFiled(),使用此种方式创建多对多表的时候,没有 add() remove() 等方法
适用方法:
- 如果第三张表没有额外的字段,就用第一种
- 如果第三张表有额外的字段,就用第三种或第一种
方法二:
models.py:
from django.db import models # 书 class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) price = models.DecimalField(max_digits=5, decimal_places=2) def __str__(self): return self.title # 作者 class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name # 手动创建作者和书籍关联的第三张表 # 此时在 ORM 层面,作者和书籍就没有多对多的关系了 class Author2Book(models.Model): id = models.AutoField(primary_key=True) author = models.ForeignKey(to="Author") # 作者 id book = models.ForeignKey(to="Book") # 书籍 id
在数据库中添加数据
author 表:
book 表:
author2book 表:
多对多的操作:
orm.py:
import os if __name__ == '__main__': # 加载 Django 项目的配置信息 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite2.settings") # 导入 Django,并启动 Django 项目 import django django.setup() from app02 import models # 多对多的查询 # 查询 id 是 2 的作者关联的书籍的 id ret = models.Author2Book.objects.filter(author_id=2).values_list("book_id") print(ret) ret = [i[0] for i in ret] # 得到关联的书籍的 id # 通过书籍的 id 查询 id 是 2 的作者关联的书籍名 ret = models.Book.objects.filter(id__in=ret) print(ret)
运行结果:
这里的 [i[0] for i in ret] 是为了取元组中的 id:2、3,然后通过 id:2、3 获取它们的书籍
方法三:
models.py:
from django.db import models # Create your models here. # 书 class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) price = models.DecimalField(max_digits=5, decimal_places=2) def __str__(self): return self.title # 作者 class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() # 通过 through,through_fields 来指定使用创建的第三张表来构建多对多的关系 books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book",)) def __str__(self): return self.name # 手动创建作者和书籍关联的第三张表 class Author2Book(models.Model): id = models.AutoField(primary_key=True) author = models.ForeignKey(to="Author") # 作者id book = models.ForeignKey(to="Book") # 书籍 id class Meta: unique_together = ("author", "book") # 建立唯一约束
在数据库中添加与 app02 一样的数据
多对多的操作
orm.py:
import os if __name__ == '__main__': # 加载 Django 项目的配置信息 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite2.settings") # 导入 Django,并启动 Django 项目 import django django.setup() from app03 import models ret = models.Author.objects.get(id=2).books.all() # 获取 id 为 2 的作者关联的所有书籍 print(ret)
运行结果:
该方法中没有 remove() 方法,可以使用下面的方法:
models.Author2Book.objects.get(author_id=1, book_id=1).delete()
没有 django ORM 封装的那些快捷方法,我们要自己手动修改第三张表