Django学习笔记之model篇(三)-- 表关系及多表查询

表关系的建立

建立学院信息表、学生信息表、课程表、学生详情表,
表关系如下:

学院信息表    《= 一对多  ForeignKeyField   =》  学生信息表

学生信息表 《= 一对一  OneToOneField =》 学生详细信息表

课程表      《= 多对多  ManyToManyField =》学生信息表

在model中建立以下几个模型类:

# models.py
from django.db import models

# 学院表
class Department(models.Model):
    d_id = models.AutoField(primary_key=True)
    d_name = models.CharField(max_length=30)

    def __str__(self):
        return "Department<d_id=%s,d_name=%s>"%(self.d_id,
                                                self.d_name)

# 学生表
class Student(models.Model):
    s_id = models.AutoField(primary_key=True)
    s_name = models.CharField(max_length=30)
    department = models.ForeignKey('Department',
                                   null=True, #可以为空值
                                   related_name='student', # 反向查询用(就不_set了:d1.student_set.all() -》d1.student )
                                   on_delete=models.CASCADE)   # 外键,自动关联表的主键 级联删除

    def __str__(self):
        return "Student<s_id=%s, s_name=%s,department_id=%s >"%(self.s_id,
                                                                self.s_name,
                                                                self.department_id)

# 学生选课表
class Course(models.Model):
    c_id = models.AutoField(primary_key=True)
    c_name= models.CharField(max_length=30)
    student = models.ManyToManyField('Student',
                                     related_name='course',
                                     ) # 多对多   生成第三张关系表

    def __str__(self):
        return "Course<c_id=%s,c_name=%s,student=%s>"%(self.c_id,
                                                       self.c_name,
                                                       self.student)

# 学生详情表
class Stu_detail(models.Model):
    s_id = models.OneToOneField('Student',on_delete=models.CASCADE)  # 一对一, 级联删除
    s_age = models.IntegerField()
    gender = models.BooleanField(default=1)
    city = models.CharField(max_length=30)

    def __str__(self):
        return "s_id=%s,s_age=%s,s_gender=%s"%(
                                            self.s_id,
                                            self.s_age,
                                            self.gender
        )

执行完makemigrations 和migrate之后,会发现生成了5张表,这是因为ManyToManyField关系生成了5第三张关系表。

python manage.py shell 我们进入项目的目录,进入IDLE操作演示数据库的操作语句更方便:

1.进入IDLE
2.查看当前的目录路径
3.导入我们项目中的模型类

一对多表关系数据的添加:

往数据表student中添加数据的第一种方式:

s1 = Student(s_name='xiaoming',department_id=1)
s1.save()

往数据表student中添加数据的第二种方式:

# 先在Department里面创建一条数据d1再进行操作
s2 = Student(s_name='小红')
s2.department_id=d1
s2.save()

1.第一种方式就是跟之前的一样,用传参的方法添加,需要注意的是外键的值必须是关联表中已经存在的值.
2.第二种方式是用的属性赋值的方式,因为我们在模型类有定义了一个department的属性,而这个属性的对象的类型必须是department表的类实例对象

表关联对象的访问:

s1.department
#  属性取值,会拿到的=d1

# 通过管理器反向访问
d1.student_set.all()
# 在Foreignkey里面设置related_name='student',这样就可以直接用名字而不是_set的形式了
d1.student.all()

#这个是实例对象
s1.departmnet

# 下面3个是管理器
d1.student
s1.course
c1.student
#

Django学习笔记之model篇(三)-- 表关系及多表查询

处理关联对象的一些方法:

    # 一对多,多的那头就有这个管理器,就有以下方法
    # 管理器才能用add,create,clear,remove方法
    d1 = Department.objects.get(d_id=1)
    s1 = Student.objects.get(s_id=1)
    c1 = Course.objects.get(c_id=1)
    # print(d1,s1,c1)
    print(d1.student.all()) # 查询到学院的所有学生, 通过一对多关系,管理器.all()
    print(s1.department) # 模型类里面的属性,直接访问
    print(c1.student) # 管理器 多对多
    print(c1.student.all()) # 报名这个课程的学生
    # print(s1.course_set.all()) # 学生报了哪些课, 反向查询,可以用related_name去改
    print(s1.course.all()) # 学生报了哪些课, 反向查询用related_name  管理器

1.add(obj1, obj2, …) 添加的已经存在数据库的数据
添加一指定的模型对象到关联的对象集中

    ## add 必须是在数据库中存在的对象  :修改
    d1.student.add(s1)    # 将s1学生改成d1学院中
    s1 = Student.objects.filter(s_id=1)
    d1 = Department.objects.filter(d_id=1)  filter取到的是QuerySet,类似于集合形式
    d1[0].student.add(s1[1])  #先拿到某个实例对象
    #例2
    s6 = Student(s_name='大大', department_id=2)
    s6.save()  # 必须保证department字段允许为空
    d1.student.add(s6) #
    s6 = Student.objects.get(s_name='小小')

2.create(**kwargs) 添加不存在的数据 ,将数据直接存入数据库
创建一个新的对象,将它保存并放在关联的对象集返回新创建的对象

s1.course.create(c_name='C语言程序设计') # 会同时向两个表格添加数据
d1.student.create(s_name='小帅')    # 给d1学院添加一个学生(之前不存在数据库中)

3.remove(obj1, obj2, …) 从关联的对象集中删除指定的模型对象。
删除的是关系表中的数据

s1.course.remove(c1)     # 学生取消某个选修课

4.clear() 从关联的对象集中删除所有的对象

注意对于所有类型的关联字段,add()、create()、remove()和clear()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法

s1.course.clear()    # 删除的是中间信息表的信息

多表查询—-跨关联关系的查询:

Django 提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段:

# 查询学院名字为‘计算机学院’的学生的信息 
Student.objects.filter(department__d_name='计算机学院')

它还可以反向工作。若要引用一个“反向”的关系,只需要使用该模型的小写的名称。

#查询学生名字中包含 '小' 的学生的学院信息
Department.objects.filter(student__s_name__contains='小')
# 查询学号为1的学生所有的课程
Course.objects.filter(student__s_id=1)
# 查询报了课程1的所有的学生
Student.objects.filter(course__c_id=1)
# 查询报了'python'课程的的学生的所属学院的信息
Department.objects.filter(student__course__c_name='python')