Django学习记录14

关系映射

数据库中的关系映射,可以有一对一、一对多、多对多。

一、一对一

当两张表出现一对一关系时,在任何一个模型类内部定义一个外键。

创建一对一映射:

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

# Create your models here.
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)

Django学习记录14
Django学习记录14
③新建man对象后使用类名=类对象名创建woman
导入类。
Django学习记录14
新建man对象man1
Django学习记录14
创建与man1对应的woman对象woman1
Django学习记录14
④新建man对象后使用类字段=类字段创建woman
Django学习记录14

最终创建的对象为
Django学习记录14

查询数据:

1、正向查询

在上例中,通过woman查询man(通过外键查询被关联对象)
直接打点访问即可获取对应类对象
eg:

woman1=woman.objects.get(womanname='李四老婆')
print(woman1.womanname,'的老公是',woman1.man.manname)

Django学习记录14

2、反向查询

反向可以使用反向属性查询到关联内容。
django在被关联类中自定义了一个与关联类名相同(小写)的隐藏属性,也可以直接使用打点访问.
但若该字段不被关联,则会报错。

man1=man.objects.get(manname='李四')
print(man1.manname,'的老婆是',man1.woman.womanname)

Django学习记录14

二、一对多

一对多则在“多”的表内创建外键。

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,故不能直接打点访问。
要通过:

#首先获取A类对象dataA
dataA=A.objects.get(***)
#1、通过B_set相当于是B类的objects,后可接所有方法,all,filter,get......甚至可以使用create创建B对象
Bs=dataA.B_set.all()
#2、使用字段筛选的方式获得
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(对象)的方法。

上一篇:Nginx+UWSGI+Django 整合安装


下一篇:Django:内建用户系统