关系映射
数据库中的关系映射,可以有一对一、一对多、多对多。
一、一对一
当两张表出现一对一关系时,在任何一个模型类内部定义一个外键。
创建一对一映射:
class A(models.Model):
pass
class B(models.Model):
a=models.OneToOneField(A,on_delete=***)
创建后外键字段名name会变为 name_id
on_delete级联删除动作指定。 可选项: ①models.CASCADE 级联删除(串联,共生死,删除一个后另一个也会删除)。django并不会在mysql层面上设置级联删除,使用ORM进行管理。 ②models.PROTECT抛出ProtectedError异常,阻止被引用对象的删除。(同mysql默认,有链接关系时不允许删除) ③SET_NULL设置ForeignKey null;允许删除,原本指向它的外键指向NULL(想要设置这种级联删除方式,外键字段必须设置null=True,即该字段必须可为空) ④SET_DEFAULT 将ForeignKey设置为其默认值(想要设置这种级联删除方式,外键字段必须设置默认值)
创建数据: 对无外键的模型类(被指向类) 直接使用create创建
a=mymodela.objects.create(a0='***')
对有外键的模型类 创建时还要给出关联字段 eg:若b0与a0关联,可使用 类名=类对象名 一一对应
b=mymodelb.objects.create(b0='***',a0=a)
或者直接使用外键的字段来对应, 对应外键字段=字段内容
b=mymodelb.objects.create(b0='***',a0_id='***')
eg:创建丈夫、妻子类,一一对应。 ①新建一个app wife(记得注册) ②新建两个模型类man、woman woman中的man字段与man模型类对应
from django.db import models
class man(models.Model):
manname=models.CharField(max_length=50,default='')
class woman(models.Model):
womanname=models.CharField(max_length=50,default='')
man=models.OneToOneField(man,on_delete=models.CASCADE)
③新建man对象后使用类名=类对象名创建woman 导入类。 新建man对象man1 创建与man1对应的woman对象woman1 ④新建man对象后使用类字段=类字段创建woman
最终创建的对象为
查询数据:
1、正向查询
在上例中,通过woman查询man(通过外键查询被关联对象) 直接打点访问即可获取对应类对象 eg:
woman1=woman.objects.get(womanname='李四老婆')
print(woman1.womanname,'的老公是',woman1.man.manname)
2、反向查询
反向可以使用反向属性查询到关联内容。 django在被关联类中自定义了一个与关联类名相同(小写)的隐藏属性,也可以直接使用打点访问. 但若该字段不被关联,则会报错。
man1=man.objects.get(manname='李四')
print(man1.manname,'的老婆是',man1.woman.womanname)
二、一对多
一对多则在“多”的表内创建外键。
class A(models.Model):
pass
class B(models.Model):
a=models.ForeignKey(A,on_delete=***)
创建字段同一对一方式,仍然是两种方法。
查询方式正向同一对一,仍然是打点访问获取对象。反向查询不同 使用例子来说明: eg:
class A(models.Model):
pass
class B(models.Model):
a=models.ForeignKey(A,on_delete=***)
在通过A查看B即为反向查询,由于一个A可以对应好多B,故不能直接打点访问。 要通过:
dataA=A.objects.get(***)
Bs=dataA.B_set.all()
Bs=B.objects.filter(a=dataA)
三、多对多
mysql通过依赖第三张表来实现。 django无需手动创建第三张表,仍使用类似的特殊属性来实现。 语法: 在关联的两个类中的任意一个加上
class A(models.Model):
pass
class B(models.Model):
a=models.ManyToManyField(A)
其实该操作本质还是django自动创建了第三张表,但在操作中并不需要关系它,直接使用django内部属性对其进行操作即可。 创建、查询方式均同一对多的反向查询。 eg:
class Author(models.Model):
authorname=models.CharField(max_length=50,default='')
class Book(models.Model):
bookname=models.CharField(max_length=50,default='')
author=models.ManyToMany(Author)
创建时先创建哪个无所谓,可自由创建、关联。 eg:创建一本书《入狱101招》,由张三、李四两个作者编著。 ①
author1=Author.objects.create(authorname='张三')
author2=Author.objects.create(authorname='李四')
book1=author1.book_set.create(bookname='入狱101招')
author2.book_set.add(book1)
②
book1=author1.book_set.create(bookname='入狱101招')
author1=Author.Book.create(authorname='张三')
author2=book.Author.create(authorname='李四')
book1.Author.add(author2)
查询: 同一对多中的一查多方法,不过正向为mybook.Author.all() 反向为myauthor.Book_set.all()
总结!!! 外键所在类对其关联类操作时,直接使用: 外键所在类对象名.对应类对象名.create/all/filter…() 当反向操作时,则使用: 对应类对象名.外键所在类对象名_set.create/all/filter…() 当两个对象都存在时,若要绑定,则使用add(对象)的方法。
|