B-08 Django-第二部分(熟练掌握)-模型(Model)设计-数据访问操作(记录查询-跨表)

模型(Model)设计-数据访问操作(记录查询-跨表)

回顾

a、模型(Model)设计流程过程说明

第一步-配置使用数据库
第二步-定义模型类
第三步-迁移数据
第四步-访问使用数据

b、数据访问操作基本API

目标

前面已经介绍了如何快速入门,现在开始熟练掌握一些知识。前面我们已经定义了数据模型,接下来,我们通过数据模型,并对数据进行增删改查,而进行增删改查操作,我们一般是在视图逻辑中进行操作。

  • 掌握定义模型类-数据访问操作(记录查询-跨表)

一、跨表记录查询

关键点:正向查询按字段,反向查询按表名。
注意表名为对应模型类名称的小写

1.1、一对一关系的跨表记录查询操作

1.1.1、表结构与数据示例

在这里插入图片描述

1.1.2、模型代码示例
class Teacher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10, verbose_name="教师名称")

    class Meta:
        db_table = 't_teacher'  # 定义表名为t_teacher

    def __str__(self):
        # 默认显示类的name字段
        return self.name


class TeacherDetail(models.Model):
    id = models.AutoField(primary_key=True)
    telephone = models.CharField(verbose_name='手机号', max_length=11)
    teacher_id = models.OneToOneField(to='Teacher', to_field='id', db_column='teacher_id', on_delete=models.CASCADE)

    class Meta:
        db_table = 't_teacher_detail'  # 定义表名为t_teacher

    def __str__(self):
        # 默认显示类的name字段
        return self.id

代码说明:
可以看出 Teacher和TeachDetail是一对一的关系,由于OneToOneField 定义在TeacherDetail中。故:

  • 正向查询:通过 t_teacher_detail 表信息查询 t_teacher 表的信息为正向查询。
  • 反向查询:通过 t_teacher 表信息查询 t_teacher_detail 表的信息为反向查询。
1.1.3、查询代码示例
a、基于对象的跨表查询
# 正向查询-查询手机号为13000000001的老师名字
teacher_detail_obj = TeacherDetail.objects.filter(telephone="13000000001").first()
teacher_name = teacher_detail_obj.teacher_id.name
print(teacher_name)
# 反向查询-查询老师名为张三的手机号
teacher_obj = Teacher.objects.filter(name="张三").first()
telephone = teacher_obj.teacherdetail.telephone
print(telephone)

执行结果

张三
13000000001
b、基于下划线的跨表查询

Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

# 正向查询-查询手机号为13000000001的老师名字
qs_001 = TeacherDetail.objects.filter(telephone="13000000001").values_list("teacher_id__name").first()
print(qs_001)
teacher_name = qs_001[0]
print(teacher_name)
# 反向查询-查询老师名为张三的手机号
qs_002 = Teacher.objects.filter(name="张三").values_list("teacherdetail__telephone").first()
print(qs_002)
telephone = qs_002[0]
print(telephone)

执行结果

('张三',)
张三
('13000000001',)
13000000001

1.2、一对多关系的跨表记录查询操作

1.2.1、表结构与数据示例

在这里插入图片描述

1.2.2、模型代码示例
class Teacher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10, verbose_name="教师名称")

    class Meta:
        db_table = 't_teacher'  # 定义表名为t_teacher

    def __str__(self):
        # 默认显示类的name字段
        return self.name
        
class Course(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16, verbose_name="课程名称", unique=True)
    teacher_id = models.ForeignKey(to='Teacher', to_field='id', on_delete=models.CASCADE, db_column="teacher_id")

    class Meta:
        db_table = 't_course'

    def __str__(self):
        # 默认显示类的name字段
        return self.name

代码说明:
可以看出 Teacher 和 Course 是一对一的关系,由于 ForeignKey 定义在 Course 中。故:

  • 正向查询:通过 t_course 表信息查询 t_teacher 表的信息为正向查询。
  • 反向查询:通过 t_teacher 表信息查询 t_course 表的信息为反向查询。
1.2.3、查询代码示例
a、基于对象的跨表查询
# 基于对象的联表查询
# 正向查询-查询课程为生物的执教老师名称
course_obj = Course.objects.filter(name="生物").first()
teacher_name = course_obj.teacher_id.name
print(teacher_name)
# 反向查询-查询张三老师所交的课
teacher_obj = Teacher.objects.filter(name="张三").first()
course_qs = teacher_obj.course_set.all()
print(course_qs)

执行结果:

张三
<QuerySet [<Course: 生物>, <Course: 体育>]>

代码说明:

  • 重点1-反向查询用表名: teacher_obj.course_set.all() 反向查询用表名,表名为对应定义模型类的小写,即 course
  • 重点2-查询对应多条:因为是一对多关系,加上 _set.all() 。获取对应的多条数据。
b、基于下划线的跨表查询
# 基于下划线的跨表查询
# 正向查询-查询课程为生物的执教老师名称
teacher_qs = Course.objects.filter(name="生物").values("teacher_id__name")
print(teacher_qs)
# 反向查询-查询张三老师所交的课
course_qs = Teacher.objects.filter(name="张三").values("course__name")
print(course_qs)

执行结果:

<QuerySet [{'teacher_id__name': '张三'}]>
<QuerySet [{'course__name': '生物'}, {'course__name': '体育'}]>

代码说明:

  • 重点1-跨表查询在 values 方法中,通过对应字段和表名的双划线表示查询对应字段。比如代码中的 teacher_id__namecourse__name

1.3、多对多关系的跨表记录查询操作

1.3.1、表结构与数据示例

在这里插入图片描述

1.3.2、模型代码示例
class Teacher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10, verbose_name="教师名称")

    class Meta:
        db_table = 't_teacher'  # 定义表名为t_teacher

    def __str__(self):
        # 默认显示类的name字段
        return self.name
        
class Class(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16, verbose_name="编辑名称", unique=True)
    grade_id = models.ForeignKey(to='Grade', to_field='id', on_delete=models.CASCADE, db_column="grade_id")
    teacher_id = models.ManyToManyField(to='Teacher', db_column="teacher_id", db_table="t_teach2cls")

    class Meta:
        db_table = 't_class'

    def __str__(self):
        # 默认显示类的name字段
        return self.name

代码说明:
可以看出 Teacher 和 Class 是多对多的关系,由于 ManyToManyField 定义在 Class 中。故:

  • 正向查询:通过 t_class 表信息查询 t_teacher 表的信息为正向查询。
  • 反向查询:通过 t_teacher 表信息查询 t_class 表的信息为反向查询。
1.2.3、查询代码示例
a、基于对象的跨表查询
# 基于对象的联表查询
# 正向查询-查询一年级的执教老师
class_obj = Class.objects.filter(name="一年一班").first()
teacher_qs = class_obj.teacher_id.all()
print(teacher_qs)
# 反向查询-查询张三老师的所教的班级
teacher_obj = Teacher.objects.filter(name="张三").first()
class_qs = teacher_obj.class_set.all()
print(class_qs)

执行结果:

<QuerySet [<Teacher: 张三>, <Teacher: 李四>]>
<QuerySet [<Class: 一年一班>, <Class: 一年二班>]>
b、基于下划线的跨表查询
# 基于下划线的跨表查询
# 正向查询-查询一年级的执教老师
teacher_qs = Class.objects.filter(name="一年一班").values("teacher_id__name")
print(teacher_qs)
# 反向查询-查询张三老师的所教的班级
course_qs = Teacher.objects.filter(name="张三").values("class__name")
print(course_qs)

执行结果:

<QuerySet [{'teacher_id__name': '张三'}, {'teacher_id__name': '李四'}]>
<QuerySet [{'class__name': '一年一班'}, {'class__name': '一年二班'}]>

二、补充知识

2.1、基于对象的跨表反向查询自定义

前面我们介绍了,基于对象的跨表反向查询,默认是使用 模型类(小写)_set ,其实我们也可以自定义。

  • 你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 XXX_set 的名称

举个列子,

class Teacher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=10, verbose_name="教师名称")

    class Meta:
        db_table = 't_teacher'  # 定义表名为t_teacher

    def __str__(self):
        # 默认显示类的name字段
        return self.name
        
class Course(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16, verbose_name="课程名称", unique=True)
    teacher_id = models.ForeignKey(to='Teacher', to_field='id', on_delete=models.CASCADE, db_column="teacher_id", related_name='teacherSet')

    class Meta:
        db_table = 't_course'

    def __str__(self):
        # 默认显示类的name字段
        return self.name

代码说明:

  • 现在我们在查询的时候就不是使用 _set 进行反向查询,而是用定义的related_name 对应的值进行。如下示例:
# 反向查询-查询张三老师所交的课
teacher_obj = Teacher.objects.filter(name="张三").first()
course_qs = teacher_obj.teacherSet.all()
print(course_qs)
  • 注意一但你在模型类的关系字段中设置了related name, 你将不能再通过_set方法来反向查询.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值