在DOM中,如果有两个表是需要关联的,但是关联方式有许多种:
- 比如一个丈夫表和一个妻子表,这两个表是一一对应的,每一个丈夫数据对象只能对应一个妻子数据,此时就可以在丈夫或者妻子的类中设置一个对方的类属性举例如下:
class Hunsband(models.Model):
name = models.CharField('丈夫', max_length = 50)
class Wife(models.Model):
name = models.CharField('妻子', max_length = 50)
hunsband = models.OneToOneField(Hunsband,
on_delete = models.CASCADE) #on_delete参数为关联删除,一般都是这个
如上代码中,在妻子类中创建了一个关联丈夫类的对象,称为外键.
在创建对象时,应该先创建没有外键的模型对象(即丈夫), 再创建有外键的模型对象(也就是妻子)并与其关联:
hus1 = Hunsband.objects.create(name = '王先生')
wife1 = Wife.objects.create(name = '王夫人', husband = hus1 |
husband_id = hus1.id) #传入外键时可以直接传入对象或者其id
此时在访问关联对象时,妻子由于有设置显式的外键husband
因此直接通过wife1.husband.name
来访问其关联对象的属性但是不能修改(这种情况称为正向查询),而丈夫对象想要访问其关联妻子时,实际上django也将其隐形分配了一个外键,名称为其关联类的类名小写字母,本例为Wife的小写wife
,因此,丈夫对象也可以直接通过这个隐形外键来访问妻子的属性hus1.wife.name
(反向查询)。
- 再比如,一个Author模型类,和一个Book模型类,一位作家可以与许多自己写的书关联,而一本书一般只能与一位作家关联,这就是一对多的关联,此时创建外键的责任必须由多的一方承担(Book),外键类型为
models.ForeignKey()
:
class Author(models.Model):
name = models.CharField(max_length = 50)
class Book(models.Model):
title = models.CharField(max_length = 50)
author = mdoels.ForeighKey(Author,on_delete = CASCADE)
如上代码,由Book类创建显式外键,参数和"一对一"一致,在创建对象时,必须先创建作家对象,再创建书,同样也需要直接将关联Author对象传入参数:
a1 = Author.objects.create(name = 'wang')
b1 = Book.objects.create(title = 'Python', author = a1)
b2 = Book.objects.create(title = 'Django', author = a1)
此时Book可以直接通过外键进行正向查询(同上),而Author对象想要访问与其关联的所有Book则需要通过反向属性book_set
books1 = a1.book_set.all()
books2 = a1.book_set.filter(筛选条件)
如上代码中,book_set
反向属性类似于objects
,可以通过调用all(),filter()
等等方法,来得到我们想要的books,这个book_set属性由该关联类名的小写+_set组成,
- 同样以数和作者举例,有时在编写教材或者翻译外国书籍时可能会有多个作者合作编写某本书,而一个作者也可能会编写多本书,以此就形成了我们的第三种情况多对多模型。
同样,我们在Author或Book上创建外键,这个显示外键我们也可以称为正向属性,类型为models.ManyToManyField()
,其实它和上面的隐形外键一样,都可以调用create(),all()等方法
,我们暂且把含有正向属性的类称为"正向类",含有隐形反向属性的类称为"反向类",举个例子:
class Author(models.Model):
name = models.CharField(max_length = 50)
class Book(models.Model):
title = models.CharField(max_length = 50)
authors = mdoels.ManyToManyField(Author) #注意不需要on_delete参数
在上面代码中,authors
即为该多对多关系的正向属性,同样系统也帮我们创建了隐式的反向属性book_set
,此时我们会发现数据库中多了一个表app_book_authors
该表名前面的为有正向属性的类小写,后面的反之:
里面存放着多组两关联对象的id关系(即多对多关系表)
在创建对象时:
book1 = Book.objects.create(title = 'Python')
book2 = Book.objects.create(title = 'Django')
author1 = Author.objects.create(name = 'wang')
author2 = Author.objects.create(name = 'ye')
首先正常创建两个类的对象,之后其实就是利用多个"一对多"来组成"多对多"的思想,我们可以用add()
函数来对某个"一"对象进行一对多的关联:
- 如果这个"一"对象是"正向类"(Book)的,则利用正向属性:
book1.authors.add(author1)
book1.authors.add(author2)
还有一种方法可以直接通过正向属性进行create()
的操作:
author3 = book1.authors.create(name = 'Chen')
这样创建了一个新的对象的同时也把这个对象与之关联,后续不再需要add操作.
- 同样,如果这个"一"对象是"反向类"(Book)的,则利用反向属性
book_set
:
author1.book_set.add(book1)
author1.book_set.add(book2)
同样可以进行create()
的操作:
book3 = author1.book_set.create(title = 'Java')
这样创建了一个新的对象的同时也把这个对象与之关联,后续不再需要add操作.