转自: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. 在github上新建一个仓库并上传本地工程

    扫盲:在github上新建一个仓库并上传本地工程 http://1ke.co/course/194 我自己新建了个项目,一步一步流程如下. zhoudd@desay:~/桌面/mini_embed_d ...

  2. CentOS 7 安装vsftpd 服务器

    在CentOS7上安装ftp服务器用于保存服务端上传的图片. 1.CentOS卸载vsftpd的方法 如果服务器上已经安装了vsftpd服务,配置出错需要卸载vsftpd服务. 1.1 查找vsftp ...

  3. Selenium Page Object(PO)设计模式

    Webdriver UI自动化测试火了好几年了,具体怎么设计自动化测试测试工程,组织测试用例完全凭借着自己的经验和习惯. 最近忽然听说了Page Object(简称PO)火了起来,也有面试的时候被问到 ...

  4. docker——镜像(image)

    镜像相关命令一览表: docker images docker tag docker inspect docker history docker search docker pull/push doc ...

  5. Font: a C++ class

    Font: a C++ class        This class is used in Fractal Generator.    Avi Examples The header fileFon ...

  6. postgresql 建模文件 LDM 转成PDM 生成 SQL问题

    LDM 转成 PDM (Tool --- GPDM ) 生成 SQL,查看全部SQL 详细步骤见下图. 1.postgresql 没有 VARCHAR2 只有 VARCHAR. 2.LDM 生成 PD ...

  7. Tornado 自定义Form,session实现方法

    一. 自定义Tornado 验证模块 我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单 ...

  8. spark-streaming读kafka数据到hive遇到的问题

    在项目中使用spark-stream读取kafka数据源的数据,然后转成dataframe,再后通过sql方式来进行处理,然后放到hive表中, 遇到问题如下,hive-metastor在没有做高可用 ...

  9. AJAX POST请求中参数以form data和request payload形式在php中的获取方式

    一.MINE TYPE问题: php对mime type为“application/x-www-form-urlencoded”(表单提交)和“multipart/form-data”(文件上传)的P ...

  10. Selenium+Python定位实例

    常见的定位方式参见:http://www.cnblogs.com/ranxf/p/7928732.html 1.ID定位(find_element_by_id) <input class=&qu ...