当前位置: 主页 > 日志 > Python >

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

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

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

设计模型如下:

from django.db import models

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()
    
    def __unicode__(self):
        return self.name
    
    class Meta:
        db_table = "author"     
    
class Book(models.Model):
    title = models.CharField(max_length=200)
    authors = models.ManyToManyField(Author)
    
    def __unicode__(self):
        return self.title
    
    class Meta:
        db_table = "book"  

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

CREATE TABLE `author` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `first_name` varchar(30) NOT NULL,
    `last_name` varchar(40) NOT NULL,
    `email` varchar(75) NOT NULL
)
;
CREATE TABLE `book_authors` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `book_id` integer NOT NULL,
    `author_id` integer NOT NULL,
    UNIQUE (`book_id`, `author_id`)
)
;
ALTER TABLE `book_authors` ADD CONSTRAINT `author_id_refs_id_22051734` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`);
CREATE TABLE `book` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `title` varchar(200) NOT NULL
)
;
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)与现有系统集成,关系表已经存在。

定义方法如下:

# coding: utf-8
from django.db import models

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()
    
    def __unicode__(self):
        return self.name
    
    class Meta:
        db_table = "author"     
    
class Book(models.Model):
    title = models.CharField(max_length=200)
    authors = models.ManyToManyField(Author, through='BookAuthor') # 注意多了through参数
    
    def __unicode__(self):
        return self.title
    
    class Meta:
        db_table = "book"
        
class BookAuthor(models.Model):
    book = models.ForeignKey(Book)
    author = models.ForeignKey(Author)
    created_at = models.DateTimeField(auto_now_add=True) # 我要添加额外的字段
    
    class Meta:
        db_table = "book_author_relationship" # 我需要用自定义的名称

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

BEGIN;
CREATE TABLE `author` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `first_name` varchar(30) NOT NULL,
    `last_name` varchar(40) NOT NULL,
    `email` varchar(75) NOT NULL
)
;
CREATE TABLE `book` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `title` varchar(200) NOT NULL
)
;
CREATE TABLE `book_author_relationship` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `book_id` integer NOT NULL,
    `author_id` integer NOT NULL,
    `created_at` datetime NOT NULL
)
;
ALTER TABLE `book_author_relationship` ADD CONSTRAINT `author_id_refs_id_6b774382` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`);
ALTER TABLE `book_author_relationship` ADD CONSTRAINT `book_id_refs_id_7cf7763a` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`);
CREATE INDEX `book_author_relationship_752eb95b` ON `book_author_relationship` (`book_id`);
CREATE INDEX `book_author_relationship_337b96ff` ON `book_author_relationship` (`author_id`);
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()

[日志信息]

该日志于 2012-05-05 11:27 由 redice 发表在 redice's Blog ,你除了可以发表评论外,还可以转载 “Django的Many-to-Many(多对多)模型” 日志到你的网站或博客,但是请保留源地址及作者信息,谢谢!!    (尊重他人劳动,你我共同努力)
   
验证(必填):   点击我更换验证码

redice's Blog  is powered by DedeCms |  Theme by Monkeii.Lee |  网站地图 |  本服务器由西安鲲之鹏网络信息技术有限公司友情提供

返回顶部