Django数据表关联(多对一)

Django数据表关联

后端系统开发中, 数据库设计是重中之重。特别是前后端分离的系统, 后端的职责基本就是数据管理, 开发的代码几乎都是围绕数据操作的。尤其是数据库表和表之间的关系的设计 ,设计的一个难点就是各种表之间的关联关系 。

Django数据表关联关系映射

数据表之间常见的3种关联关系就是:多对一(一对多) , 一对一 , 多对多。Django 中定义了三种关系类型的字段用来描述数据库表的关联关系:多对一(Foreignkey)、一对一(OneToOneFiled)、以及多对多(ManyToManyFiled)。

多对一(一对多): 1个人可以有多辆车,但一辆车只能对应一个车主

请添加图片描述

models.ForeignKey     # 定义在多方

多对多:一个作者可以写很多本书,一本书的完成也可以由多个作者共同创作

请添加图片描述

models.ManyToManyField #定义在任意1方,只能定义在1方,不能双方都定义

一对一:1个人只能有一个身份证号,一个身份证号也只能对应1个人

在这里插入图片描述

models.OneToOneField   

多对一关系类型

这种类型在数据库中体现是外键关联关系,它在和其他的 Model 建立关联同时也和自己建立关联,用来描述一对多的关系,Django 会自动将字段的名称添加“_id”作为列名,ForgienKey 的定义如下:

class django.db,model.ForeignKey(to,on_delete,**options)

必填参数

它有两个必填参数:to,指定所关联的 Model,它的中取值可以是直接引用其他的 Model,也可以是 Model 所对应的字符串名称;on_delete,当删除关联表的数据时,Django 将根据这个参数设定的值确定应该执行什么样的 SQL 约束。

on_delete 可以理解为 MySQL 外键的级联动作,当主表执行删除操作时对子表的影响,即子表要执行的操作,Django 提供的可选值如下所示:

  • CASCADE,级联删除,它是大部分 ForeignKey 的定义时选择的约束。它的表现是删除了“主”,则“子”也会被自动删除。
  • PROTECT,删除被引用对象时,将会抛出 ProtectedError 异常。当主表被一个或多个子表关联时,主表被删除则会抛出异常。
  • SET_NULL,设置删除对象所关联的外键字段为 null,但前提是设置了选项 null 为True,否则会抛出异常。
  • SET_DEFAULT:将外键字段设置为默认值,但前提是设置了 default 选项,且指向的对象是存在的。
  • SET(value):删除被引用对象时,设置外键字段为 value。value 如果是一个可调用对象,那么就会被设置为调用后的结果。
  • DO_NOTHING:不做任何处理。但是,由于数据表之间存在引用关系,删除关联数据,会造成数据库抛出异常。

可选参数

除了必填参数以外,ForeignKey 还有一些常用的可选参数需要关注。

  • to_field:关联对象的字段名称。默认情况下,Django 使用关联对象的主键(大部分情况下是 id),如果需要修改成其他字段,可以设置这个参数。但是,需要注意,能够关联的字段必须有 unique=True 的约束。
  • db_constraint:默认值是 True,它会在数据库中创建外键约束,维护数据完整性。通常情况下,这符合大部分场景的需求。如果数据库中存在一些历史遗留的无效数据,则可以将其设置为 False,这时就需要自己去维护关联关系的正确性了。
  • related_name:这个字段设置的值用于反向查询,默认不需要设置,Django 会设置其为“小写模型名 _set”。
  • related_query_name:这个名称用于反向过滤。如果设置了 related_name,那么将用它作为默认值,否则 Django 会把模型的名称作为默认值。

语法格式

一个A类实例对象关联多个B类实例对象,外键定义在多的一方(B类)。例:老师 关联 课程

class Teacher(model.Model):
....

class Course(model.Model):
    属性 = models.ForeignKey(多对一中"一"的模型类, ...)
模型创建

执行python manage.py startapp lecture新增一个名为讲座lecture的应用

lecture应用目录下的 models.py文件中,创建模型,命名为 TeacherStudyLecture,一个老师可以开展多个讲座,老师和讲座的关系为一对多

# 老师模型
class Teacher(SchoolMember):
    # 姓名
    name = models.CharField(max_length=100, null=False)
    # 学院
    college = models.CharField(max_length=256)
    # 专业
    major = models.CharField(max_length=256)

    # 覆盖对象对外的字符串表现形式
    def __str__(self):
        return self.name
    
# 讲座模型  继承django自带的模型基类
class StudyLecture(models.Model):
    lectureTeacher = models.ForeignKey(Teacher,on_delete=models.CASCADE)   # 如果删除了老师,关联的讲座也会被删除

    # 讲座名称
    name = models.CharField(max_length=256, null=False)
    # 讲座地点
    address = models.CharField(max_length=256)
    # 讲座开始时间
    start_time = models.DateTimeField(null=True)
    # 讲座状态
    status = models.BooleanField(default=True)
    # 讲座限制人数
    limits = models.IntegerField(default=1000)

    # 覆盖对象对外的字符串表现形式
    def __str__(self):
        return self.name

更改完 models.py文件后需要进行数据库迁移操作,依次执行以下命令即可:

python manager.py makemigrations
python manager.py migrate

同样可以通过Django Admin后台的方式去添加数据,在应用目录下的 admin.py 文件中进行声明

from django.contrib import admin    #Django自动在admin.py文件中导入
from lecture.models import *

admin.site.register([Teacher,StudyLecture])   # 注册模型

通过 Admin后台插入多条老师和讲座的数据

在这里插入图片描述

通过sql、Navicat工具等方式去插入数据也是可以的

外键关联查询
正向查询

正向查询是多方查询单方,因为外键是定义在多方。通过模型对象的外键 即modelObj.foreigner 进行查询

打开pycharm的Terminal终端,输入命令python manage.py shell 打开Django自带命令行,输入指令from lecture.models import Teacher, StudyLecture导入lecture应用下的Teacher、StudyLecture模型类。

输入指令 lecture= StudyLecture.objects.all().first() 查询数据库里的第一条讲座的数据,返回单个模型数据对象(一个对象实例)。此时可以通过lecture.namelecture.addresslecture.start_time去获取讲座的名称、开展地点和开始时间,这些信息都是存在lecture_studylecture表里的,可以通过StudyLecture模型类进行获取。

老师和讲座的关系是一对多,一个老师可以开展多个讲座,外键 lectureTeacher 定义在讲座的模型里,通过讲座去查询老师的信息,这种查询就是正向查询

输入命令:lecture.lectureTeacher ,通过模型对象的外键 lectureTeacher 去获取这个讲座的老师的信息,得到的内容是单个模型数据对象(一个对象实例):<Teacher: 王老师>,可以通过 lecture.lectureTeacher.namelecture.lectureTeacher.collegelecture.lectureTeacher.major去获取这个数据对象里老师的姓名和所属专业信息。这种就是通过通过模型对象的外键获取想要的信息,就是正向查询

反向查询

反向查询是单方查找多方,通过模型对象的外键模型的小写_setmodelObj.foreigner_set 进行查询

通过老师去查询讲座的信息,这种查询是反向查询。

输入指令 teacher = Teacher.objects.get(name='王老师') 查询数据,返回单个模型数据对象。

通过模型对象的外键模型的小写_set teacher.studylecture_set.all()查询数据,返回<QuerySet [<StudyLecture: 测试讲座>, <StudyLecture: 功能测试讲座>]>是一个QuerySet对象(一个对象实例列表),里面有<StudyLecture: 测试讲座> , <StudyLecture: 功能测试讲座>两个模型数据对象(对象实例)。
这种就是通过反向查询的方式获取的,可以通过下标的方式获取列表里第一个讲座的名称、开展时间和开展地点等信息:teacher.studylecture_set.all()[0].nameteacher.studylecture_set.all()[0].address

路由、视图与模板

在lecture应用下的urls.py文件中新增子路由

from django.urls import path
from lecture import views as lecture_view

# 子路由列表
urlpatterns = [
    path('lectures/', lecture_view.lectures),  # 讲座管理页面
    path('lectures/<int:lecture_id>', lecture_view.lecture_detail),  
	
    path('Teachers/',lecture_view.Teachers), #讲座讲师管理页面
    path('Teachers/<int:teacher_id>',lecture_view.Teachers_detail),
]

在lecture应用目录下的views.py文件中新增lectureslecture_detail两个视图函数

from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

from lecture.models import *

# Create your views here.

# 讲座管理页面
def lectures(request):
    # 从数据库获取实时的数据
    lecture_list = StudyLecture.objects.all()
    # 返回一个模板内容
    return render(request,'lectures.html',{'lecture_list':lecture_list})

# 讲座详情页
def lecture_detail(request,lecture_id):
    # 获取到当前页面的讲座数据对象
    try:
        lecture = StudyLecture.objects.get(id=lecture_id)
    except:
        return render(request,'404.html')

    return render(request,'lecture_detail.html',{'lecture':lecture})

将数据返回给前端模板文件

lectures.html

{% extends "base.html" %}
{% block title%}讲座管理{% endblock %}

{% block content%}
  <ul class="list-group">
    {% for lecture in lecture_list %}
      <li class="list-group-item text-center">
      <a href="/lecture/lectures/{{ lecture.id }}">{{ lecture }}</a>
      </li>
    {% endfor %}
  </ul>
{% endblock %}

lecture_detail.html

{% extends 'base.html' %}
{% block title%}讲座详情页{% endblock %}
{% block content%}
  <div class="panel panel-info">
    <div class="panel-heading"> 讲座详情页 </div>
    <div class="panel-body">
      <p>讲座名称:{{ lecture.name }}</p>
      <p>讲座时间:{{ lecture.start_time }}</p>
      <p>讲座地址:{{ lecture.address }}</p>
      <p>讲座讲师:
          <a href="/lecture/Teachers/{{ lecture.lectureTeacher.id }}" >{{ lecture.lectureTeacher.college }}{{ lecture.lectureTeacher.major }}{{ lecture.lectureTeacher.name }}</a>
      </p>

      <p><a href="/lecture/lectures" class="btn btn-info">返回讲座内容列表</a></p>
    </div>
  </div>
{% endblock %}

讲座讲师这里{{ lecture.lectureTeacher.college }}{{ lecture.lectureTeacher.major }}{{ lecture.lectureTeacher.name }},就是通过外键查询将讲座关联的老师的姓名和所属专业信息展示到页面上

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值