转自: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. mysql应用实例

    目录: 表结构 sql练习 1.表结构 SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- T ...

  2. 推荐系统第3周--- 大数据环境下的itemCF实现

    代码报错注意事项: 1:最后Ctrl+shift+O  导入包2:导入mahout包3:新建datafile文件包,在其下面新建csv文件

  3. WooCommerce Shortcode 简码使用方式说明

    WooCommerce 自帶的几个简易代码,可以用来插入文章和页面內容里面.下面简码安裝时会自动建立,因此,应该不需要使用在其他地方 : [woocommerce_cart] – 顯示購物車頁面 [w ...

  4. 88. Merge Sorted Array(从后向前复制)

    Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...

  5. [转]Earth Mover's Distance (EMD)

    转自:http://www.sigvc.org/bbs/forum.php?mod=viewthread&tid=981 Earth Mover's Distance (EMD)原文: htt ...

  6. doc命令下查看java安装路径

    在doc窗口下使用命令:set  java_home 即可查看.

  7. [转]eclipse 配置黑色主题 Luna 方式三

      虽然以前也使用eclipse的黑色主题,但是配置起来稍微麻烦一点. 这里先声明,下面的方式适合最新版本的Eclipse Luna,旧的版本可以下载我提供的这个插件,并将其放在eclipse目录下的 ...

  8. docker基本用法和命令

    1.安装docker 检查有没有curl which curl 如果没有用以下命令可安装:sudo apt-get install curl 通过官方提供的脚本安装最新docker curl -sSL ...

  9. 【Python】高阶函数

    filter def is_palindrome(n): L = str(n) i = 0 j = len(L) - 1 while i != j: if L[i] != L[j]: return F ...

  10. Django学习笔记之URL标签的使用

    期初用django 开发应用的时候,完全是在urls.py 中硬编码配置地址,在views.py中HttpResponseRedirect()也是硬编码转向地址,当然在template 中也是一样了, ...