Django之Model关系
前言
本文记录个人对Django三种模型关系(一对一,一对多,多对多)理解,由于日后回顾,若有不同意见欢迎批评指正。
软件版本:Django2.2,python3.7
一对一关系(OneToOneField)
Django中使用OneToOneField来进行一对一关系约束,其本质是通过外键关联数据,并设置unique来保证一对一。具体例子如下:
from django.db import models
class Husband(models.Model):
h_name = models.CharField(max_length=20)
class Wife(models.Model):
w_name = models.CharField(max_length=20)
married_man = models.OneToOneField(Husband, null=True, on_delete=models.SET_NULL)
妻子与丈夫就是一个常见的一对一关系,关于上诉例子有两点需要特殊说明的。
1. 主从表关系
由于在Wife中声明了OneToOneField,因此Wife为从表,Husband为主表,在其他类型中也是如此,在那个表中声明了对应关系,那么该表就是从表。
2. on_delete 有五种常用的选项
2.1 models.CASCADE(默认选项)
若设置on_delete=models.CASCADE,或不设置on_delete,当Wife关联的Husband被删除时,Wife也会被一同删除,反之,Husband不会被删除。
2.2 models.PROTECT
保护选项,设置该选项后,若要删除Husband的数据,且该数据关联Wife中的数据,此时系统会报错提示数据受保护,反之可以正常删除。
2.3 models.SET_NULL
空值选项,设置该选项后,若要删除Husband的数据,且该数据关联Wife中的数据,可正常删除,且Wife不会被删除,此时会把Wife的关联数据设置为空,注意使用此选项时必须设置null=True(允许空值),否则会出现异常。
2.4 models.SET_DEFAULT
默认值选项,该选项与SET_NULL类似,当删除与Wife绑定的Husband时,会把Wife的关联数据设置为默认值,注意使用此选项时必须设置Default=你设置的默认值,否则会出现异常。
2.5 models.SET()
该选项与2.3,2.4讲述的选项类似,当删除与Wife绑定的Husband时,会把Wife的关联数据设置为括号内的值,注意防止设置的值与其他设置冲突。
3. 主从表间的数据访问
从表可以通过属性名(married_man)访问主表的数据,主表可以通过关联表的表名(wife)获取从表数据,如下:
from django.test import TestCase
from .models import Husband, Wife
class SeModelTests(TestCase):
def test_one2one(self):
hus = Husband.objects.create(h_name='h')
wi = Wife.objects.create(w_name='w', married_man=hus)
self.assertEqual(wi.married_man.h_name, 'h')
self.assertEqual(hus.wife.w_name, 'w')
一对多关系(ForeignKey)
Django中的一对多关系,就是通过外键关联两个表,具体例子如下:
from django.db import models
class Grades(models.Model):
g_name = models.CharField(max_length=20)
class Students(models.Model):
s_name = models.CharField(max_length=20)
grade = models.ForeignKey(Grades, on_delete=models.CASCADE)
学生与年级也是常见的一对多的关系,一个年级对应多个学生,若年级被删除了,那对应的学生也不存在,因此设置年级为主表,学生为副表。
主从表间的数据访问
与一对一相同的是:从表可以通过属性名(grade)访问主表的数据。不同之处在于主表可以通过关联表的表名(student)+_set获取从表数据,其中表明_set也是Manager的一个子类,同objects一样有get,filter等方法,具体如下:
from django.test import TestCase
from .models import Grades, Students
class SeModelTests(TestCase):
def test_one2many(self):
g = Grades.objects.create(g_name='g1')
s1 = Students.objects.create(s_name='s1', grade=g)
s2 = Students.objects.create(s_name='s2', grade=g)
self.assertEqual(g.students_set.get(pk=1).s_name, 's1')
self.assertEqual(s1.grade.g_name, 'g1')
多对多关系(ManyToManyField)
Django中通过新建一个记录表的方式来进行多对多数据的关联,实例如下:
from django.db import models
class People(models.Model):
p_name = models.CharField(max_length=20)
class Things(models.Model):
t_name = models.CharField(max_length=20)
grade = models.ManyToManyField(People)
人与事是常见的多对多关系,一个人有多个事要完成,一件事也可以由多个人完成。
主从表间的数据访问
多对多关系中,主表与从表间访问数据的方法都与一对多中,主表访问从表的方式类似,都通过Manager的子类来进行访问,其中主表使用的子类命名规则为从表表明_set(thing_set),从表使用的子类就是对应属性名(worker)具体如下:
from django.test import TestCase
from .models import People, Things
class SeModelTests(TestCase):
def test_many2many(self):
p1 = People.objects.create(p_name='p1')
p2 = People.objects.create(p_name='p2')
t1 = Things()
t1.t_name = 't1'
t1.save()
t2 = Things()
t2.t_name = 't2'
t2.save()
t1.worker.add(p1, p2)
p1.things_set.add(t2)
self.assertEqual(p1.things_set.get(pk=t2.id).t_name, 't2')
self.assertEqual(t1.worker.get(pk=p1.id).p_name, 'p1')