zoukankan      html  css  js  c++  java
  • 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()

     

  • 相关阅读:
    selenium--启动不同的浏览器
    selenium--文件下载
    selenium--常用的获取元素属性
    Python读取yaml文件
    python读Excel方法(xlrd)
    Python--unittest框架
    Python--os模块
    git fork后提交pull request到原作者,别人的pull request我们要怎样merge融合
    GitHub fork的使用
    4.Factory Pattern(工厂模式)
  • 原文地址:https://www.cnblogs.com/zknublx/p/5959295.html
Copyright © 2011-2022 走看看