Django数据表关联(一对一)

一对一关系类型

OneToOneFiled 继承自 ForeignKey,在概念上,它类似 unique=TureForeignKey,它与 ForeignKey 最显著的区别在于反向查询上,ForeignKey 反向查询返回的是一个QuerySet对象(一个对象实例列表),含两个或两个以上模型数据对象;而 OneToOneFiled 反向查询返回的是一个对象实例(单个模型数据对象)。

一对关系类型的使用和场景相对其他两种关联关系要少,经常用于对已有 Model 的扩展,例如我们可以对 Teacher 表进行扩展,添加类似用户手机号、地址、邮箱等字段。此时就可以新建一个 Model,命名为TeacherInfo,并定义一个字段与 Teacher 表一对一关联。这样就实现了教师信息拓展表TeacherInfo与教师Teacher 表一对一关联

语法格式

class A(model.Model): 
	...

class B(model.Model):    
	属性 = models.OneToOneField(A)
模型创建

Lecture 应用目录下的 models.py文件中,创建一个模型,命名为 Teacher,再创建一个 TeacherInfo模型用于记录教师信息

# 老师模型--需要继承django自带的模型基类
class Teacher(models.Model):
    # 姓名
    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
    

# 讲师信息模型 一对一
class TeacherInfo(models.Model):
    teacher = models.OneToOneField(Teacher,on_delete=models.CASCADE)    # 如果删除了老师表中的老师,关联的老师信息也会被删除
    
    identityCard = models.CharField(max_length=18,unique=True)	# 身份证号
    phone = models.CharField(max_length=11, unique=True)  # 手机号 唯一 最大长度11
    email = models.EmailField()  # 邮箱
    officeAddress = models.CharField(max_length=256)    # 办公地址

老师的数据信息是一对一,学生的数据信息也可以是一对一

from django.db import models

# 学生模型--需要继承django自带的模型基类
class Student(models.Model):
    # 姓名
    name = models.CharField(max_length=100, null=False)
    # 学院
    college = models.CharField(max_length=256)
    # 专业
    major = models.CharField(max_length=256)
    # 班级
    grade = models.CharField(max_length=256)

    # 覆盖对象对外的字符串表现形式
    def __str__(self):
        return self.name
    
    
# 学生信息模型 一对一
class StudentInfo(models.Model):
    student = models.OneToOneField(Student,on_delete=models.CASCADE)    # 如果删除了学生表中的学生,关联的学生信息也会被删除
    identityCard = models.CharField(max_length=18,unique=True)	# 身份证号
    phone = models.CharField(max_length=11, unique=True)  # 手机号 唯一 最大长度11
    email = models.EmailField()  # 邮箱
Model的继承模型

在 Django 中每个 Model 都是一个 Pyhton 类,Django Model 的继承与 Python 类的继承是一样的,只是 Django 要求所有自定义的 Model 都必须继承自 django.db.models.Model。通过类之间的继承 Django 会对自定义的 Model 自动添加了两个属性分别是 id 和 objects。

对比 Student类和 Teacher类,都拥有相同的字段:姓名、学院、专业,而 Student类比 Teacher类多了一个班级字段;对比 StudentInfo类和 TeacherInfo类,都拥有相同的字段:身份证号、手机号、邮箱,而 TeacherInfo类比 StudentInfo类多了一个办公地址字段;对于这些相同的内容,是可以提取出来的,将这些字段统一定义在抽象基类中,避免去重复定义这些字段

# 定义抽象基类模型
class SchoolMember(models.Model):
    # 姓名
    name = models.CharField(max_length=100, null=False)
    # 学院
    college = models.CharField(max_length=256)
    # 专业
    major = models.CharField(max_length=256)

    # 声明是抽象基类
    class Meta:
        abstract = True


# 学生模型--继承SchoolMember抽象基类
class Student(SchoolMember):
    # 班级
    grade = models.CharField(max_length=256)

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


# 老师模型--继承SchoolMember抽象基类
class Teacher(SchoolMember):

    # 覆盖对象对外的字符串表现形式
    def __str__(self):
        return self.name
    
    
# 定义抽象基类模型
class SchoolMemberInfo(models.Model):
    identityCard = models.CharField(max_length=18, unique=True)  # 身份证号
    phone = models.CharField(max_length=11, unique=True)  # 手机号 唯一 最大长度11
    email = models.EmailField()  # 邮箱

    # 声明是抽象基类
    class Meta:
        abstract = True


# 学生信息模型--继承SchoolMemberInfo抽象基类
class StudentInfo(SchoolMemberInfo):
    # 如果删除了学生表中的学生,关联的学生信息也会被删除
    student = models.OneToOneField(Student,on_delete=models.CASCADE)

    
# 讲师信息模型--继承SchoolMember抽象基类
class TeacherInfo(SchoolMemberInfo):
    # 如果删除了老师表中的老师,关联的老师信息也会被删除
    teacher = models.OneToOneField(Teacher, on_delete=models.CASCADE)
    officeAddress = models.CharField(max_length=256)  # 办公地址

SchoolMemberStudentTeacher 3 个类映射到数据库后,只会被定义为两个数据表。 分别是 StudentTeacher。 它们都继承自 SchoolMember,且继承了父表中的所字段值,同时自身又自定义了新的字段。所以,它们对应的字段分别如下所示:

  • Student数据表:有 id、name、college、major 和 grade 5 个字段;
  • Teacher 数据表:有 id、name、college和major 4个字段。

关于 Model 的元数据继承关系,遵循以下几个规则:

  • 抽象基类中定义的元数据,子类中没有定义,子类会继承基类中的元数据;
  • 抽象基类中定义的元数据,子类也定义了,子类优先级更高;
  • 子类可以定义自己的元数据,即不出现在抽象基类中的元数据。

在定义抽象基类时,需要注意,如果定义了 ForeignKey 或 ManyToManyField 类型的字段,并且设置了 related_name 或者 related_query_name 参数,由于继承关系,子类也会拥有同样的字段,所以,在子类中的反向名称和查询名称是唯一的。

路由、视图与模板

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

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

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

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

# 讲座讲师
def Teachers(request):
    # 从数据库获取讲座讲师数据
    Teacher_list = Teacher.objects.all()
    # 返回模板页面展示讲座讲师数据
    return render(request,'Teachers.html',{'Teacher_list':Teacher_list})


# 讲座讲师详情
def Teachers_detail(request,teacher_id):
    # 获取讲师数据
    try:
        teacher = Teacher.objects.get(id=teacher_id)
    except:
        return render(request,'404.html')

    return render(request,'Teacher_detail.html',{'teacher':teacher})

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

Teachers.html

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

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

Teacher_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>姓名:{{ teacher.name }}</p>
      <p>手机号:{{ teacher.teacherinfo.phone }}</p>
      <p>邮箱:{{ teacher.teacherinfo.email }}</p>
      <p>办公地点:{{ teacher.teacherinfo.officeAddress }}</p>

      <p>关联讲座:
        {% for lecture in  teacher.studylecture_set.all  %}
          <a href="/lecture/lectures/{{ lecture.id }}">{{ lecture }}</a>
        {% endfor %}
      </p>
      <p><a href="/lecture/Teachers/" class="btn btn-info">返回讲师列表</a></p>
    </div>
  </div>
{% endblock %}

这里关联讲座,用到了多对一外键关联查询中的反向查询,通过老师去查询关联的讲座。teacher.studylecture_set.all返回一个QuerySet对象(一个对象实例列表):

<QuerySet [<StudyLecture: 易经学习>, <StudyLecture: 历史讲座>]>,里面有<StudyLecture: 易经学习>, <StudyLecture: 历史讲座>两个模型数据对象(对象实例),通过for循环将数据展示到前端模板

在这里插入图片描述

手机号、邮箱和办公地点,则是通过与 Teacher模型 一对一关联的 TeacherInfo模型 查询获得的

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值