Django - ORM 多对多关系 - 中间关系表的创建方式探讨

目录

多对多关系 - 三种中间表的创建方式 - 优劣总结

方式一、手动创建第三张表

方式二、自动创建第三张表 - MandyToManyField

方式三、半自动创建第三张表 -- 手动创建第三张表+ManyToMany建立关系(推荐使用)


多对多关系 - 三种中间表的创建方式 - 优劣总结

  • 手动创建第三张表(A表,B表,A2B表),A、B内不建立与A2B的关联关系 -- 增删改查操作繁杂 不建议使用

  • 自动创建第三张表 -- 删改查很方便,但是字段固定,对中间关系表添加字段难以实现

  • 半自动创建第三张表(手动穿件第三张表(中间关系表),自动建立三表的关系) -- 建议使用

    • through('A2B表名') :指定手动创建的关系表(A2B)

    • through_fields('A2B表内当前表关系字段','A2B表内关系表的字段'):中介模型

方式一、手动创建第三张表

注意:

  • A,B 表内未建立与A2B表的关联
  • 查询必须通过第三张表进行 ,无法使用基于下划线的跨表查询
  • 添加操作必须操作三张表,A表添加对象,B表获取对象,A2B表保存二者对象
# models内三个表的创建

from django.db import models


# Create your models here.

class Book(models.Model):
    # 默认会创建id
    name = models.CharField(max_length=32)


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


class Book2Author(models.Model):
    id = models.AutoField(primary_key=True)
    # 手动通过外键关联字段
    book=models.ForeignKey(to='Book',to_field='id')
    author=models.ForeignKey(to='Author',to_field='id')
from app01 import models

# 查询红楼梦这本书所有的作者 全手动

book=models.Book.objects.filter(name='红楼梦').first()
authors=models.Book2Author.objects.filter(book=book).values_list('author_id')
print(authors)
ll=[i[0] for i in authors]
# ll=[1,2]
author_list=models.Author.objects.filter(id__in=ll)
print(author_list)

#   给红楼梦这本书添加n这个作者
author=models.Author.objects.filter(name='n').first()
book = models.Book.objects.filter(name='红楼梦').first()

#去中间表存
ret=models.Book2Author.objects.create(book=book,author=author)
# 给红楼梦这本书,删除lqz这个作者

方式二、自动创建第三张表 - MandyToManyField

注意:

  • related_name 关联对象反向引用描述符 - 通过book可以引用到Book表中对象
  • 只需要操作两个表在models内
  • 以为未在models内操作第三张表,所以后期对第三张表的操作无法添加字段(可以通过服务器,但是不推荐)
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")
    # verbose_name admin中显示的表名称


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    # 通过ORM自带的ManyToManyField自动创建第三张表
    books = models.ManyToManyField(to="Book", related_name="authors")
    # related_name 关联对象反向引用描述符 - 通过book可以引用到Book表中对象
    # Book.object.filter(name = '红楼梦').authors.all() - 获取book表内红楼梦的所有作者
    # 可解决外键重名问题
from app03 import models as m3

# 第三种方式,全自动创建

# 查询红楼梦这本书的所有作者
book = m3.Book.objects.filter(title='红楼梦').first()
print(book)
# 通过 related_name="authors"
print(book.authors.all())
# 通过反向查询 被relate_name代替无法操作
# print(book.author_set.all())

# 正向查询 查询作者名叫n1的所有书籍
a = m3.Author.objects.filter(name='n1').first()
print(a)
print(a.books.all())

#   给红楼梦这本书添加n这个作者
author = m3.Author.objects.filter(name='n1').first()
print(author)
book = m3.Book.objects.filter(title='红楼梦').first()
# 使用add添加
author.books.add(book)

方式三、半自动创建第三张表 -- 手动创建第三张表+ManyToMany建立关系(推荐使用)

注意:

  • through('A2B表名') :指定手动创建的中间关系表(A2B)

  • through_fields('A2B表内当前表关系字段','A2B表内关系表的字段'):中介模型

  • 三张表都建立了内部联系,可以使用双下划綫和基于对象的正方形查询方式

from django.db import models
# Create your models here.

# 手动创建第三张表,查询还方便的查询
class Book(models.Model):
    # 默认会创建id
    name = models.CharField(max_length=32)
    # 中介模型,手动指定第三张中间表是Book2Author
    authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'author'))


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

    def __str__(self):
        return self.name


class Book2Author(models.Model):
    id = models.AutoField(primary_key=True)
    book = models.ForeignKey(to='Book', to_field='id')
    author = models.ForeignKey(to='Author', to_field='id')

Django - ORM 多对多关系 - 中间关系表的创建方式探讨_第1张图片

 

from app02 import models as mo2

#     第二种方式 半自动

# 基于对象的查询(存在正向反向)
# 查询红楼梦这本书所有的作者 -正向
book = mo2.Book.objects.filter(name='西游记').first()
print(book.authors.all())

# n1作者查书名 - 反向
a = mo2.Author.objects.filter(name='n1').first()
print(a.book_set.all())


# 基于双下划线的查询(可以简单忽视正反)
# 查询红楼梦这本书所有的作者的名字
ret=mo2.Author.objects.filter(book__name='西游记').values('name')
print(ret)


# 删除,给西游记这本书,删除n2这个作者
ret=mo2.Book2Author.objects.filter(book__name='西游记',author__name='n2').delete()
print(ret)

 

 

你可能感兴趣的:(Django)