Django的Many-to-Many(多对多)模型

 

Django的Many-to-Many(多对多)模型

参考:《DjangoBook2.0》 数据模型高级进阶

经典的例子:一本书有多个作者,一个作者有多本书,典型的多对多关系。

设计模型如下:

  1. from django.db import models  
  2.   
  3. class Author(models.Model):  
  4.     first_name = models.CharField(max_length=30)  
  5.     last_name = models.CharField(max_length=40)  
  6.     email = models.EmailField()  
  7.       
  8.     def __unicode__(self):  
  9.         return self.name  
  10.       
  11.     class Meta:  
  12.         db_table = "author"       
  13.       
  14. class Book(models.Model):  
  15.     title = models.CharField(max_length=200)  
  16.     authors = models.ManyToManyField(Author)  
  17.       
  18.     def __unicode__(self):  
  19.         return self.title  
  20.       
  21.     class Meta:  
  22.         db_table = "book"    

python manage.py sqlall books(App名) 看一下Django帮我们生成的数据库表结构:

  1. CREATE TABLE `author` (  
  2.     `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,  
  3.     `first_name` varchar(30) NOT NULL,  
  4.     `last_name` varchar(40) NOT NULL,  
  5.     `email` varchar(75) NOT NULL  
  6. )  
  7. ;  
  8. CREATE TABLE `book_authors` (  
  9.     `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,  
  10.     `book_id` integer NOT NULL,  
  11.     `author_id` integer NOT NULL,  
  12.     UNIQUE (`book_id`, `author_id`)  
  13. )  
  14. ;  
  15. ALTER TABLE `book_authors` ADD CONSTRAINT `author_id_refs_id_22051734` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`);  
  16. CREATE TABLE `book` (  
  17.     `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,  
  18.     `title` varchar(200) NOT NULL  
  19. )  
  20. ;  
  21. ALTER TABLE `book_authors` ADD CONSTRAINT `book_id_refs_id_77516490` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`);   

book表中并没有authors字段,其中的book_authors表就是用来存放书和作者多对多映射关系的。

 

访问多值:

一本书的所有作者:

b = Book.objects.get(id=50)

b.authors.all()

b.authors.filter(first_name='Adam')

反向也可以,一个作者的所有书:

a = Author.objects.get(id=1)

a.book_set.all()

给多对多字段添加值(添加多对多关系):

a = Author.objects.get(id=1)

b = Book.objects.get(id=50)

b.authors.add(a)

从多对多字段中删除值(删除多对多关系):

 

a = Author.objects.get(id=1)

b = Book.objects.get(id=50)

b.authors.remove(a) 或者 b.authors.filter(id=1).delete()

 

我想自定义关系表!!!

为什么?

可能的原因:

1)我想添加一些额外的字段;

2)与现有系统集成,关系表已经存在。

定义方法如下:

  1. # coding: utf-8  
  2. from django.db import models  
  3.   
  4. class Author(models.Model):  
  5.     first_name = models.CharField(max_length=30)  
  6.     last_name = models.CharField(max_length=40)  
  7.     email = models.EmailField()  
  8.       
  9.     def __unicode__(self):  
  10.         return self.name  
  11.       
  12.     class Meta:  
  13.         db_table = "author"       
  14.       
  15. class Book(models.Model):  
  16.     title = models.CharField(max_length=200)  
  17.     authors = models.ManyToManyField(Author, through='BookAuthor') # 注意多了through参数  
  18.       
  19.     def __unicode__(self):  
  20.         return self.title  
  21.       
  22.     class Meta:  
  23.         db_table = "book"  
  24.           
  25. class BookAuthor(models.Model):  
  26.     book = models.ForeignKey(Book)  
  27.     author = models.ForeignKey(Author)  
  28.     created_at = models.DateTimeField(auto_now_add=True) # 我要添加额外的字段  
  29.       
  30.     class Meta:  
  31.         db_table = "book_author_relationship" # 我需要用自定义的名称  

再看一下此时的数据库表结构:

  1. BEGIN;  
  2. CREATE TABLE `author` (  
  3.     `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,  
  4.     `first_name` varchar(30) NOT NULL,  
  5.     `last_name` varchar(40) NOT NULL,  
  6.     `email` varchar(75) NOT NULL  
  7. )  
  8. ;  
  9. CREATE TABLE `book` (  
  10.     `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,  
  11.     `title` varchar(200) NOT NULL  
  12. )  
  13. ;  
  14. CREATE TABLE `book_author_relationship` (  
  15.     `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,  
  16.     `book_id` integer NOT NULL,  
  17.     `author_id` integer NOT NULL,  
  18.     `created_at` datetime NOT NULL  
  19. )  
  20. ;  
  21. ALTER TABLE `book_author_relationship` ADD CONSTRAINT `author_id_refs_id_6b774382` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`);  
  22. ALTER TABLE `book_author_relationship` ADD CONSTRAINT `book_id_refs_id_7cf7763a` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`);  
  23. CREATE INDEX `book_author_relationship_752eb95b` ON `book_author_relationship` (`book_id`);  
  24. CREATE INDEX `book_author_relationship_337b96ff` ON `book_author_relationship` (`author_id`);  
  25. COMMIT;  

爽!

但是这样做也是有不便的地方:多对多字段的add()和remove()方法就不能用了。这里有很好的解释:http://stackoverflow.com/questions/1755591/many-to-many-relationships-with-additional-data-on-the-relationship

https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

那此时我们如何添加和删除映射关系呢?直接使用BookAuthor模型。

例如:

 

a = Author.objects.get(id=1)

b = Book.objects.get(id=50)

BookAuthor(book=b, author=a).save()

 

posted @ 2016-10-14 10:08  朝阳的向日葵  阅读(1768)  评论(0编辑  收藏  举报