转自:http://luozhaoyu.iteye.com/blog/1510635

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

  1. from django.db import models
  2. class Publisher(models.Model):
  3. name = models.CharField(max_length=30)
  4. address = models.CharField(max_length=50)
  5. city = models.CharField(max_length=60)
  6. state_province = models.CharField(max_length=30)
  7. country = models.CharField(max_length=50)
  8. website = models.URLField()
  9. class Author(models.Model):
  10. first_name = models.CharField(max_length=30)
  11. last_name = models.CharField(max_length=40)
  12. email = models.EmailField()
  13. class Book(models.Model):
  14. title = models.CharField(max_length=100)
  15. authors = models.ManyToManyField(Author)
  16. publisher = models.ForeignKey(Publisher)
  17. publication_date = models.DateField()

有出版商,作者,和书。一本书有多个作者,只有一个出版商。 
作者和出版商好理解,各一个表就是了。书应该作为几个表呢?1个和2个都可以。如果你主要是以出版商和作者为对象操作,可以把书看成一个纽带而已,书这个表里存放着出版商和作者的关系。又因为一行存不下所有作者的id(假设没有压缩),所以book表里面会有很多book会重复。所以book表的名字改成author_publisher搞不好还更妥当。 
如果你要认真的把书也看成一个表(不想看到重复的书名),那么就需要把书和作者的关系又单独提出来。这里是个多对多的关系所以用ManyToManyField,如果一对多呢?就用ForeignKey。 
我们用

  1. python manage.py sql books

查看生成的表结构

  1. BEGIN;
  2. CREATE TABLE "books_publisher" (
  3. "id" serial NOT NULL PRIMARY KEY,
  4. "name" varchar(30) NOT NULL,
  5. "address" varchar(50) NOT NULL,
  6. "city" varchar(60) NOT NULL,
  7. "state_province" varchar(30) NOT NULL,
  8. "country" varchar(50) NOT NULL,
  9. "website" varchar(200) NOT NULL
  10. )
  11. ;
  12. CREATE TABLE "books_author" (
  13. "id" serial NOT NULL PRIMARY KEY,
  14. "first_name" varchar(30) NOT NULL,
  15. "last_name" varchar(40) NOT NULL,
  16. "email" varchar(75) NOT NULL
  17. )
  18. ;
  19. CREATE TABLE "books_book" (
  20. "id" serial NOT NULL PRIMARY KEY,
  21. "title" varchar(100) NOT NULL,
  22. "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED,
  23. "publication_date" date NOT NULL
  24. )
  25. ;
  26. CREATE TABLE "books_book_authors" (
  27. "id" serial NOT NULL PRIMARY KEY,
  28. "book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED,
  29. "author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED,
  30. UNIQUE ("book_id", "author_id")
  31. )
  32. ;
  33. CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id");
  34. COMMIT;

结果确实是生成了四个表。 
其中book_authors表是关联表,不能直接插入数据,实际上也不存在叫做BookAuthors的对象。所以要插入这里面数据,建立起book和author的联系时,必须取出book实例,并给book赋值

  1. #首先是创建一个book,book创建之后才能添加联系表,这是显然的
  2. book = Book()
  3. book.save()
  4. #添加三个作者,传如一个列表
  5. book.authors = Author.objects.all()[0:3]
  6. #或者添加一个作者,传入一个实例
  7. book.authors.add(Author.objects.all()[0])
  8. #最后是save
  9. book.save()

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

  1. book.authors.all()
  2. author.book_set.all()

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

  1. select publisher_author.* from publisher_author, author where publisher_author.author_id = author.id

我们还得拿着这些author的id才能找出真正的这些author。 
而之前的ManyToManyField做了什么呢?

  1. 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

理解django的多对多ManyToManyField的更多相关文章

  1. Django中多对多关系的orm表设计

    作者的管理 1.设计表结构 出版社 书籍 作者 一个出版社出版多个书籍  1对多 书籍和作者的关系:一个作者写多本书,一本书可以是多个作者写.多对多 1)创建一张表,表中多对多的数据关系.使用 多对多 ...

  2. [diango]理解django视图工作原理

    前言:正确理解django视图view,模型model,模板的概念及其之间的关联关系,才能快速学习并上手使用django制作网页 本文主要讲解自己在学习django后对视图view的理解 在进入正文之 ...

  3. Django——20141014深入理解Django HttpRequest HttpResponse的类和实例

    深入理解Django HttpRequest HttpResponse的类和实例 了解META选项 了解中间件 理清所有模板传输模板变量的方式,并作出选择 Django模板系统:如何利用Django模 ...

  4. 理解django的框架为何能够火起来

    理解django的框架为何能够火起来 https://www.yiibai.com/django/django_basics.html https://code.ziqiangxuetang.com/ ...

  5. django的多对一,一对一,多对多关系

    from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) a ...

  6. django ORM多对多正向查询时查询返回结果为None

    表 class Books(models.Model): '''书籍''' id = models.AutoField(primary_key=True) name = models.CharFiel ...

  7. Django 之多对多关系

    1. 多对多关系 作者 <--> 书籍 1. 表结构设计 1. SQL版 -- 创建作者表 create table author( id int primary key auto_inc ...

  8. Linux下开发python django程序(django数据库多对多关系)

    1.多对多关系数据访问 models.py设置 from django.db import models # Create your models here. sex_choices=( ('f',' ...

  9. Django之多对多表之through第三张表之InlineModelAdmin后台内嵌

    话不多说,来看表结构 这里有两个表,一个是阶段表,一个是老师表,一个老师可以带多个阶段,一个阶段也可以由多个老师带,所以是多对多关系 # 阶段表 class Stage(models.Model): ...

随机推荐

  1. Flask与pyaudio实现音频数据流的传输(电话会议语音交互式应用)

    1.声卡设备验证 #查看音频设备 dong@dong-ubuntu:~$ arecord -l**** CAPTURE 硬體裝置清單 ****card 0: PCH [HDA Intel PCH], ...

  2. HDFS集中式的缓存管理原理与代码剖析

    转载自:http://www.infoq.com/cn/articles/hdfs-centralized-cache/ HDFS集中式的缓存管理原理与代码剖析 Hadoop 2.3.0已经发布了,其 ...

  3. R语言 dbWriteTable 写入数据库 为空和乱码问题

    在windows环境下 用RMySQL 写入数据库中文数据为空 或者乱码问题. 找了下资料 一般情况是 用 insert 语句插入,结合现有业务有点麻烦,放弃了. 还有一种方式换平台,由于经常在win ...

  4. 《FTL之垃圾回收、写放大和OP 》总结

    来自 http://www.ssdfans.com/?p=1840: 写放大WA: 对空盘来说(未触发GC),写放大一般为1,即Host写入多少数据,SSD写入闪存也是多少数据量(这里忽略SSD内部数 ...

  5. 04 linux用户群组和权限

    作业一: 1)新建用户natasha,uid为1000,gid为555,备注信息为“master” 2)修改natasha用户的家目录为/Natasha 3)查看用户信息配置文件的最后一行 4)为na ...

  6. 获取一个表单字段中多条数据并转化为json格式

    如图需要获取下面两个li标签里面的数据,然后传给后台:而后台接收的数据格式是json的,所以需要把两个li里面的信息转化为以下格式的. {recieverName:小红,recieverPhone:1 ...

  7. configparser模块来生成和修改配置文件

    1. 安装configparser模块 pip3 install configparser ##python2.7模块名为ConfigParser 2. 创建配置文件 import configpar ...

  8. spark2.10安装部署(集成hadoop2.7+)

    这里默认你的hadoop是已经安装好的,master是node1,slaver是node2-3,hdfs启动在node1,yarn启动在node2,如果没安装好hadoop可以看我前面的文章 因为这里 ...

  9. linux 注销其他用户

    本文主要参考:http://ysz520020.blog.163.com/blog/static/352595722011969264745 linux kill掉其他的登录用户 : 方法一: 使用 ...

  10. python3_Logging模块详解

    python的logging模块提供了通用的日志系统,可以方便第三方模块或应用使用. 简单使用 import logging # logging.config.fileConfig("./l ...