`
luozhaoyu
  • 浏览: 346689 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

理解django的多对多ManyToManyField

阅读更多
对于第一次碰到django这样类activerecord的ORM,初学者可能比较疑惑的是ManyToManyField这个字段。老鸟可以绕开,这里拿djangobook没有说明的地方来仔细解释下。
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

有出版商,作者,和书。一本书有多个作者,只有一个出版商。
作者和出版商好理解,各一个表就是了。书应该作为几个表呢?1个和2个都可以。如果你主要是以出版商和作者为对象操作,可以把书看成一个纽带而已,书这个表里存放着出版商和作者的关系。又因为一行存不下所有作者的id(假设没有压缩),所以book表里面会有很多book会重复。所以book表的名字改成author_publisher搞不好还更妥当。
如果你要认真的把书也看成一个表(不想看到重复的书名),那么就需要把书和作者的关系又单独提出来。这里是个多对多的关系所以用ManyToManyField,如果一对多呢?就用ForeignKey。
我们用
python manage.py sql books
查看生成的表结构
BEGIN;
CREATE TABLE "books_publisher" (
    "id" serial NOT NULL PRIMARY KEY,
    "name" varchar(30) NOT NULL,
    "address" varchar(50) NOT NULL,
    "city" varchar(60) NOT NULL,
    "state_province" varchar(30) NOT NULL,
    "country" varchar(50) NOT NULL,
    "website" varchar(200) NOT NULL
)
;
CREATE TABLE "books_author" (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(40) NOT NULL,
    "email" varchar(75) NOT NULL
)
;
CREATE TABLE "books_book" (
    "id" serial NOT NULL PRIMARY KEY,
    "title" varchar(100) NOT NULL,
    "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED,
    "publication_date" date NOT NULL
)
;
CREATE TABLE "books_book_authors" (
    "id" serial NOT NULL PRIMARY KEY,
    "book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED,
    "author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED,
    UNIQUE ("book_id", "author_id")
)
;
CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id");
COMMIT;

结果确实是生成了四个表。
其中book_authors表是关联表,不能直接插入数据,实际上也不存在叫做BookAuthors的对象。所以要插入这里面数据,建立起book和author的联系时,必须取出book实例,并给book赋值
#首先是创建一个book,book创建之后才能添加联系表,这是显然的
book = Book()
book.save()
#添加三个作者,传如一个列表
book.authors = Author.objects.all()[0:3]
#或者添加一个作者,传入一个实例
book.authors.add(Author.objects.all()[0])
#最后是save
book.save()

那么,使用ManyToManyField的好处是不是就是省去了创建一个简单联系表(如果不满足于这么简单的表,也可一通过through参数来指明存在的表)?使用它我们还可以做到通过把一张表中某键值在另一张表中全部映射的对象找出来。比如把某书的所有作者,或者某作者的所有书找出来。
book.authors.all()
author.book_set.all()

可是如果用最土的三张表的方法:一个publisher,一个author,一个publisher_author,在PublisherAuthor模型不指定ManyToManyField而只用ForeignKey也可以这么方便么?(找出映射的对象)
猜想是可以的……可以查出publisher或author对应的PublisherAuthor对象……就相当与只执行了
select publisher_author.* from publisher_author, author where publisher_author.author_id = author.id

我们还得拿着这些author的id才能找出真正的这些author。
而之前的ManyToManyField做了什么呢?
select * from publisher where publisher.id in (select publisher_id from publisher_author, author where publisher_author.author_id = author.id) 

嗯……多对多关系只是帮我们多做了一步嵌套子查询,并包装成publisher集而已,更方便,但未必更高效。

注:以上SQL是伪的,未经过查验,根据结果反推,ORM至少是做了这些工作的,只会更多,不会更少。如果有机会我会再查查它到底执行了什么,如果知道结果的朋友也请告诉我吧XD
1
5
分享到:
评论

相关推荐

    Django ManyToManyField 跨越中间表查询的方法

    在Django框架中,ManyToManyField是一种用于处理多对多关系的数据字段,它允许一个模型实例与多个其他模型实例关联。在本例中,我们有两个模型:`Column`(栏目)和`Article`(文章)。`Column`模型代表不同的文章...

    Django之多对多查询与操作方法详解

    本文将对 Django 之多对多查询与操作方法进行详细的介绍,并提供实践示例代码,以便读者更好地理解和应用此概念。 多对多关系 在 Django 中,多对多关系是指两个模型之间的关系,可以是多个实例之间的关系。例如,...

    《Django实战》源码(第一、第二版) .zip

    通过这个源码包,你不仅可以深入理解Django的各个组件,还能看到它们如何协同工作,从而提升你的实战开发能力。在实践中遇到问题时,可以参考源码中的解决方案,或者查阅书籍中的相关章节来获取更详细的解释。这将是...

    解决Django后台ManyToManyField显示成Object的问题

    首先,要理解ManyToManyField是Django ORM中用于定义两个模型之间多对多关系的字段类型。举个例子,如果我们有两个模型:Book和Author,一个Book可以有多个Author,一个Author也可以写多本Book,那么在Book模型中就...

    基于Django ORM、一对一、一对多、多对多的全面讲解

    理解并熟练运用Django ORM中的一对一、一对多和多对多关系是开发Django应用的基础,它们使得数据库设计变得更加灵活,同时也简化了数据库操作。在实际项目中,根据业务需求合理选择关系类型,能有效提高代码的可读性...

    项目实战 Python Django 个人网站 电影推荐网站 完整代码

    此外,评论功能通常涉及多对多关系,Django的ManyToManyField字段可以帮助处理这种关系。 5. **代码注释与可读性** 项目提供的代码注释详细,有助于初学者理解代码逻辑和Django的工作原理,对于自我学习和团队协作...

    Django官方文档中文翻译(models部分)

    3. 多对多(ManyToManyField):表示多对多关系,一个模型的实例可以关联多个其他模型的实例,反之亦然。 六、序列化与反序列化 1. 序列化:将模型实例转换为JSON或其他格式,以便在网络上传输或保存到文件。 2. ...

    models_django管理_django_django的一个model_

    首先,让我们深入理解Django的Model类。在`models.py`文件中,每个类通常代表数据库中的一个表,类的属性定义了表的字段。例如,你可以定义一个User模型,它可能包含id(主键)、username、password、email等字段。...

    Django_ORM.zip_Oldboy 3_django_django orm_orm_session

    在"Oldboy 3"的课程中,可能详细讲解了如何设置和使用Django ORM进行数据库操作,比如模型的定义、字段类型、模型间的关系(一对一、一对多、多对多),以及如何进行查询(查询集、过滤、排序、分组等)。...

    Django学习资源3333

    模型类定义字段属性,如CharField、IntegerField等,以及可能的约束和关系,如外键(ForeignKeys)和一对多关系(ManyToManyField)。在数据库操作方面,Django提供了 queryset API,用于执行数据库查询,以及模型...

    django模型专题笔记

    - **多对多关系(ManyToManyField)**:两个模型之间可以直接建立多对多关系,无需中间表。例如,`Tag` 和 `Book` 可以有多个互相关联的标签: ```python class Tag(models.Model): name = models.CharField(max_...

    7. Django 模型与数据库

    字段类型多种多样,包括基本类型如`CharField`(字符字段)、`IntegerField`(整数字段)和`DateTimeField`(日期时间字段),还有复杂类型如`ManyToManyField`(多对多关系)和`ForeignKey`(一对多关系)。...

    Django Xadmin多对多字段过滤实例

    首先,让我们理解多对多字段(ManyToManyField)在Django中的工作原理。多对多字段允许一个模型实例与多个其他模型实例关联,反之亦然。例如,一个用户可以属于多个组,一个组也可以有多个用户。在数据库层面,这种...

    在Django框架中运行Python应用全攻略

    #### 二、理解Django中的模型 在Django中,模型是用于描述数据的基本单元,通常用于定义应用程序的数据结构。以下是一个关于作者、出版商和书籍的示例模型,用于演示如何使用Django模型来表示这些实体。 ##### 模型...

    python毕业设计之学生成绩管理系统源码(django+mysql+LW).zip

    首先,我们要理解Django是Python的一个高级Web开发框架,它提供了强大的MVT(Model-View-Template)模式,使得开发者能快速地构建复杂的Web应用程序。 在“教师管理”模块中,系统允许管理员或教师添加、编辑和删除...

    Django+Python搭建的购物网站

    在本文中,我们将深入探讨如何使用Django框架和Python编程语言来构建一个功能完善的购物网站。Django,作为Python中最受欢迎的Web开发框架之一...理解并掌握这些知识点,将有助于你成功地开发出自己的Django购物网站。

    django_auto_test.zip

    7. `ManyToManyField`: 定义多对多关系,如 `tags = models.ManyToManyField('Tag')`,允许一个模型实例与多个其他实例关联。 8. `NullBooleanField`: 允许值为 `True`, `False` 或 `None`。 9. `TextField`: 用于...

    Python库 | django-modelforms-0.1.1.tar.gz

    此外,`django-modelforms`还支持模型的多对一和多对多关系。如果你的模型中有一个外键或一个ManyToManyField,`ModelForm`同样可以处理,将关联的模型转换为选择框或多个选择框,供用户选择。 在实际开发中,`...

Global site tag (gtag.js) - Google Analytics