首页 技术 正文
技术 2022年11月23日
0 收藏 690 点赞 3,214 浏览 3185 个字

转自: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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,955
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,479
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,291
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,108
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,740
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,774