Django多对多关系详解:自动建表、手动建表及级联删除
本文详细介绍Django中多对多关系的实现方式。涵盖自动创建第三张关联表的机制与注意事项,包括处理已有数据时的迁移报错解决。同时演示如何手动创建第三张表并建立关联。内容包含通过add、remove、clear方法管理关联对象,以及级联删除对多对多关系的影响,提供完整的代码示例与操作步骤。
Django多对多关系基础与自动建表
首先创建Author作者模型,并在Book书籍模型中定义与Author的多对多关系。外键字段可以放置在任意一方,但在Django的多对多关系中,通常不需要显式定义外键,而是通过ManyToManyField隐式处理。
class Author(models.Model):
name = models.CharField(max_length=32)
#在Author表中创建第三张表,与book表创建多对多关系一样的效果
# books = models.ManyToManyField(Book)
#再重新生成数据库,因为新增了多对多关系,book表会新增字段,所以直接重新生成数据库就会报错,
在Book模型中关联Author模型时,如果Author模型定义在Book模型之前,可以直接引用Author类名。
若将Author作为字符串引用(即加上引号),Django会在加载完所有模型后再进行查询解析,此时Author模型可以在全局任何位置定义。
这种方式允许Author模型在Book模型之后定义,只要保证在应用加载结束时能解析到即可。
如果不加引号直接引用Author类,则必须确保Author模型在Book模型之前定义,否则会出现NameError。
在Book模型中,通过ManyToManyField字段创建与Author表的多对多关系。
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5 , decimal_places=2)
#书籍与出版社是一对多,书是多,出版社是一,外键(子表)建在多的表中,
#publish 作为一个外键 与Book 表建立一对多关系,默认绑定到Book 的主键id上
publish = models.ForeignKey(Publish,)
执行数据库迁移生成表结构时需注意:如果Book表中已存在数据,直接迁移会报错。因为Django会自动在Book表中新增一个author_id字段(用于存储关联关系),而原有数据没有该字段,导致不兼容。因此,在生成迁移前需先清空Book表中的数据。
执行以下命令生成并应用迁移:python manage.py makemigrations,然后python manage.py migrate。
迁移完成后,数据库中会自动生成一张名为book_author的第三张表。该表包含一个主键和两个外键(分别指向Book和Author),这是Django自动创建的关联表。此时即可开始添加书籍数据。

若需手动插入数据并绑定Book与Author的多对多关系,可以通过Django ORM进行操作。

在views视图函数中,先获取Book表中的一个book对象,通过book_obj.authors.all()查看该book关联的作者列表。
对于id=1的这本书,如果没有关联作者,返回None;如果有作者,则返回一个QuerySet对象集合,其中包含所有关联的作者对象。
#给第三张表添加关系,
#看下authors对象
book_obj = Book.objects.get(id=1)#获取一个书籍的对象,有可能是多个作者写的,是一个集合对象,
#获取id=1 这本书的作者集合对象,类似列表结构
print(book_obj.authors) #gu_orm.Author.None ,是id=1的这本书,没有作者,所以得到一个None,-----------------------------
#如果给Book和author绑定了关系,添加值,就会得到一个Queryset集合,
print(book_obj.authors.all())
#< QuerySet[ < Author: egon >, < Author: alex >, < Author: yuan >] >---------------------------------------
---------------
多对多关系的代码实现与管理
方法1:通过获取单个对象来创建多对多关系,并逐一添加。
下面通过代码实现多对多关系的创建过程。
首先,建议删除原第三张表中的测试数据,以确保操作清晰。
步骤1:获取一个Book对象实例。
book_obj = Book.objects.get(id=1)#获取一个书籍的对象,有可能是多个作者写的,是一个集合对象,
步骤2:获取一个或多个Author对象实例。
author1 = Author.objects.get(id=1)
author2 = Author.objects.get(id=2)
步骤3:使用add方法将author1和author2添加到book_obj对象中。这将把这两个作者对象关联到该书。
#book表与author表绑定关系,把2个作者对象添加到,关联到Book对象
book_obj.authors.add(author1,author2)
执行相关URL并刷新数据库,验证关联是否成功建立。

===
方法2:通过获取所有对象集合来创建多对多关系。注意使用*号将列表拆分为单个对象传入。
#先获取一个book对象,
book_obj = Book.objects.get(id=1)
#方法2 ,把所有的author加到book对象中
author_list = Author.objects.all()
book_obj.authors.add(*author_list)
=====
解除关联关系可使用clear()方法清除所有关联,或使用remove()方法删除指定的关联关系。
#解除关联关系
book_obj.authors.clear()#解除了书与作者的所有关系,
#指定删除Book与作者的关系,先获取要解除关联的对象,然后用remove的方法,
author = Author.objects.get(name = 'alex')
book_obj.authors.remove(author)
----
级联删除:当删除一个对象时,使用delete()方法,相关联的一对多和多对多关系也会被自动删除。
book_obj.delete()
----
手动创建第三张表与级联删除
ManyToManyField会自动生成第三张关联表,无需手动干预。
也可以手动创建第三张表来管理多对多关系,这提供了更多的灵活性。
# manytomany,会自动生成第三张表,现在自己可以手动创建第3张表,
class book2author(models.Model):
book = models.ForeignKey("Book")
author = models.ForeignKey("Author")
手动创建后,数据库中会多出如book2author这样的表。
在views视图函数中,可以通过实例化手动创建的第三张表模型并调用save()方法来添加记录。
#----给自己手动创建的第三张添加记录,实列化对象,用save保存
b2a = book2author(book_id=2,author_id=1)#括号里面可以写集合,作者的集合对象,进行关联,
b2a.save()
return HttpResponse('ok')
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









