关系数据库最强⼤大的地⽅方在于“关系”,也即表和表之间是有关联的,这种关联有三种类型:

  • 一对⼀
  • 一对多
  • 多对多

一对一

  • 应用场景:用于复杂表的拆分,扩展新功能
  • 实现:其实是使用外键实现的,然后对外键添加了唯一约束

例如有一个学生和一个档案。一个学生只对应一个档案。这种关系就是一对一的关系。学⽣生表是主表,档案表是从表。从表中有一个外键和学⽣生表关联,并且要求外键取值唯⼀。对应关键字为:OneToOneField
例如我们定义这样一个模型:

class Student(models.Model):
    sno = models.CharField(max_length=16, primary_key=True)
    sname = models.CharField(max_length=30)
    ssex = models.CharField(max_length=2)


class Archives(models.Model):
    ano = models.CharField(max_length=16, unique=True)
    student = models.OneToOneField(Student, on_delete=models.CASCADE)

数据查询

  • 跨关系查询
    def lookup(request):
    #根据档案查学⽣生
    student =Student.objects.get(archives__idcard='041804')
    #根据学⽣生查档案
    archive = Archives.objects.get(student__sno='180501')
    return HttpResponse(archive)
  • 主获取从(正向查询)隐形属性 默认就是级联模型的名字
def student(request):
    stu = Student.objects.first()
    arc = stu.archives
    return HttpResponse(arc.ano)
  • 从获取主(反向查询)显性属性,就是属性的名字
def student(request):
    arc = Archives.objects.first()
    stu = arc.student
    return HttpResponse(stu.sname)

数据删除

  • 在级联表中会分为主表从表

谁声明关系谁就是从表。
当系统遭遇不可避免毁灭时,只能保留一张表,这个表就是你的主表

在定义OneToOneField的时候有一个必须要加的参数就是on_delete一般有三种

1.CASCADE

  • 从表数据删除,主表不受影响
  • 主表数据删除,从表数据直接删除

2.PROTECT

  • 主表如果存在级联数据,删除动作受保护,不能成功
  • 主表不存在级联数据,可以删除成功
  • 一般用于防止误操作

3.SET

  • SET_NULL 允许为NULL
  • SET_DEFAULT 存在默认值
  • SET() 指定值

4.DO_NOTHING

  • 什么也不做

一对多

比如说一个教室又很多学生,一个学生只能在一个教室上课。教室和学生就属于一对多的关系。

一对多一般将主表中的主键并到从表中做外键

在模型中⽤用ForeignKey表示多对一

例如:

class Room(models.Model):
    rnum = models.CharField(max_length=5, null=True)

    class Meta:
        db_table = 'room'


class Student(models.Model):
    sname = models.CharField(max_length=16, null=True)
    room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='room')

    class Meta:
        db_table = 'student'
  • 跨关系查询
def students(request):
    # 根据姓名查班级
    room = Room.objects.get(student__sname='张三')
    print(room)
    # 根据班级查姓名
    stu = Student.objects.filter(room__rnum='301')
    print(stu)
    return HttpResponse('ok')
  • 主获取从(正向查找) 隐性属性
def room(request):
    classroom = Room.objects.last()
    stu = classroom.room.first()   # 这个room是related_name的room
    return HttpResponse(stu.sname)
  • 从获取主(反向查找)显性属性
def room(request):
    stu = Students.objects.first()
    classroom = stu.room.rnum
    return HttpResponse(classroom)

多对多

一个买家可以购买多件商品,一件商品可以被多个买家购买,买家和商品之间构成多对多关系,多对多关系必然会⽣生成一张中间表:买家-商品表,记录商品和买家的关系,该表包含商品表主键和买家表的主键

首先我们先创建一个模型:

class Customers(models.Model):
    cname = models.CharField(max_length=16)


class Goods(models.Model):
    gname = models.CharField(max_length=16)
    gcustomer = models.ManyToManyField(Customers, related_name='gcustomer')

然后进行迁移,注意 这里迁移映射后会出现三个表,多出来的那个表就是中间表,记录商品和买家的关系

通过查看第三个表的DDL我们也可以发现:

create index one_goods_gcustomer_customers_id_a49466e1
    on one_goods_gcustomer (customers_id);

create index one_goods_gcustomer_goods_id_11e611d4
    on one_goods_gcustomer (goods_id);

create unique index one_goods_gcustomer_goods_id_customers_id_77dfe5e7_uniq
    on one_goods_gcustomer (goods_id, customers_id);

关系表中存储关系表的主键,通过多个外键实现的

多个外键值不能同时相等

  • 从获取主
    使用属性,属性是一个Manager子类
    def buy(request):
      customs = Customers.objects.last()
      goods = Goods.objects.last()
      goods.gcustomer.add(customs)
      return HttpResponse('购买成功')

  • 主获取从
    也是Manager子类,操作和从操作主完全一样
    def buy(request):
      customs = Customers.objects.first()
      goods = Goods.objects.first()
      customs.gcustomer.add(goods)
      return HttpResponse('购买成功')

通过这样操作就可以在商品和顾客之间的关系表中记录商品和买家的关系

最后修改:2020 年 07 月 09 日
如果觉得我的文章对你有用,请随意赞赏