两表联查
常见的两表关系:
一对多:ForeignKey
-
举例:一个学生对应多个地址
-
一般通过外键实现
-
需要在“多”的那个模型中使用ForeignKey
-
使用on_delete指定级联删除策略:
-
CASCADE:当父表数据删除时,相对应的从表数据会被自动删除
-
SET_NULL:当父表数据删除时,相对应的从表数据会被自动设置为null值
-
PROTECT:当父表数据删除时,如果有相对应的从表数据会抛出异常
-
SET_DEFAULT: 当父表数据删除时,相对应的从表数据会被自动设置为默认值,还需要额外指定default=True
-
一对一:OneToOneField
-
举例:一个人对应一个身份证号
-
数据字段设置 unique
-
可以在任何一个模型类使用OneToOneField
多对多:ManyToManyField
-
举例:一个学生有多个老师,一个老师有多个学生
-
一般通过第三个表来实现关联
-
可以在任何一个模型类使用ManyToManyField
一对多/多对一
创建学生与地址表(学生是一,地址是多)
class Student(models.Model):# 模型类中不需要指定 id字段,会自动生成# 数据库的可变字符串类型 varchar(20)name = models.CharField(max_length=20)age = models.IntegerField()create_time = models.DateTimeField('创建时间')class Address(models.Model):# CASCADE:当父表数据删除时,相对应的从表数据会被自动删除student = models.ForeignKey(Student, on_delete=models.CASCADE)detail = models.CharField(max_length=200)
增
需求:增加一个叫王老五的学生,给王老五添加一个地址
# 一对多,多对一 新增
def foreignkey_add(request):# 增加学生,和单表一样,采用 create方法直接生成数据,不需要再去调用savestudent = Student.objects.create(name='王老五', age=10,create_time=timezone.now())# 增加地址,通过外键_id形式给外键赋值 idAddress.objects.create(detail="河北省", student_id=student.id)return HttpResponse("一对多,新增成功!!!")
删
需求:删除id=2的学生,同时删除该学生对应的地址
# 一对多,多对一 删除
def foreignkey_del(request):# 删除学生(因创建表的时候,两表定义的关系为:on_delete=models.CASCADE ,所以删除学生,其对应的地址也会被删除)Student.objects.filter(id=2).delete()return HttpResponse("一对多,删除成功!!!")
改
需求:修改id=4的学生,修改id=3的地址
# 一对多,多对一 修改
def foreignkey_update(request):# 修改学生Student.objects.filter(id=4).update(name="小明")# 修改地址(修改需要用 filter 获取地址的查询集,使用 get 报错)Address.objects.filter(id=3).update(detail='武汉市')return HttpResponse("一对多,修改成功!!!")
查
正向查询: 先查询学生,再通过学生查询出其地址
反向查询: 先查询地址,再通过地址查询出学生
# 一对多,多对一 查询
def foreignkey_query(request):# 正向查询:通过学生,查询学生对应的地址信息# 查询id为2 的学生 以及他对应的地址信息# 1. 查询学生对象student = Student.objects.get(id=2)# 2. # 通过django内置的属性 模型类_set, 可以查询出学生下的所有地址addressSet = student.address_set.all()res='正向查询:该学生所有的地址是:<br />'# 遍历所有对象for q in addressSet:res += str(q.id) + "." + q.detail + " <br />"res = '反向查询:地址对应的学生是:<br />'# 反向查询:通过地址,查询对应学生# 查询id为3的地址,以及对应的学生# 1. 查询地址对象address = Address.objects.get(id=3)# 2. 获取对应的学生信息 (对象.外键.关联模型类的字段)studentName = address.student.nameres +=studentName+ " <br />"return HttpResponse(res)
一对一
创建学生与身份证信息表(学生是一,身份证是一)
class Student(models.Model):# 模型类中不需要指定 id字段,会自动生成# 数据库的可变字符串类型 varchar(20)name = models.CharField(max_length=20)age = models.IntegerField()create_time = models.DateTimeField('创建时间')class Idcard(models.Model):remark = models.CharField(max_length=200,verbose_name="备注")num=models.CharField(max_length=20,verbose_name="身份证号")# CASCADE:当父表数据删除时,相对应的从表数据会被自动删除student = models.OneToOneField(to=Student, on_delete=models.CASCADE)
注:学生表之前就有,本次只需要新增 Idcard 表即可,添加完模型后,再次执行迁移命令:
# 重新生成迁移文件
python manage.py makemigrations score# 同步数据库
python manage.py migrate
增
# 一对一 新增
def oneToone_add(request):# 增加学生student = Student.objects.create(name='小王', age=14,create_time=timezone.now())# 增加身份信息Idcard.objects.create(num="123456789",remark="这是身份证", student_id=student.id)return HttpResponse("一对一,新增成功!!!")
删
# 一对一 删除
def oneToone_del(request):# 删除学生(其对应的身份信息也会被删除)Student.objects.filter(id=5).delete()# 删除身份信息(学生不会被删除)# Idcard.objects.filter(id=1).delete()return HttpResponse("一对一,删除成功!!!")
改
# 一对一 修改
def oneToone_update(request):# 修改学生Student.objects.filter(id=2).update(name="小王王")# 修改身份Idcard.objects.filter(id=2).update(remark='这是护照')return HttpResponse("一对一,修改成功!!!")
查
# 一对一 查询
def oneToone_query(request):# 正向查询:通过学生,查询学生对应的身份信息student = Student.objects.get(id=6)idcard_num = student.idcard.numres='正向查询:该学生所有的身份id是:<br />'+idcard_num+"<br />"# 反向查询:通过身份,查询对应学生idcard = Idcard.objects.get(id=2)student_name = idcard.student.nameres +='反向查询:身份对应的学生是:<br />'+student_name+ " <br />"return HttpResponse(res)
多对多
创建学生与老师表(一个学生对应多个老师,一个老师对应多个学生)
class Student(models.Model):# 模型类中不需要指定 id字段,会自动生成# 数据库的可变字符串类型 varchar(20)name = models.CharField(max_length=20)age = models.IntegerField()create_time = models.DateTimeField('创建时间')class Teacher(models.Model):name = models.CharField(max_length=20)gender = models.IntegerField(choices=((0,"男"),(1,"女")),verbose_name='性别')# 多对多没有 on_delete参数# 在多对多的情况,有专门的第三张表,存储 对应关系,表本身并没有字段来存储对应关系,此时删除任意数据,不影响另一张表数据student = models.ManyToManyField(to=Student)
执行完迁移命令后,出现以下表:
增
# 多对多 新增
def manyTomany_add(request):# 增加老师teacher = Teacher.objects.create(name='王老师', gender=1)# 增加学生student = Student.objects.create(name='小三', age=20,create_time=timezone.now())# 给老师添加多个学生# 对象.关联字段.add(关联的student表的id)teacher.student.add(2,3)return HttpResponse("多对多,新增成功!!!")
删
# 多对多 删除
def manyTomany_del(request):# 多对多关联字段的删除,要使用 remove 来进行关系的断开,而不是直接使用 delete# remove 只会断开数据之间的联系,但是不会将数据删除teacher = Teacher.objects.get(id=1)student = Student.objects.get(id=2)# 老师对象.关联字段.remove(学生对象)teacher.student.remove(student)return HttpResponse("多对多,删除成功!!!")
改
先解除原有关联,再重新添加新的关系
查
# 多对多 查询
def manyTomany_query(request):# 正向查询:通过学生,查询学生对应的老师student = Student.objects.get(id=3)teacher_list = student.teacher_set.all()res = '正向查询:该学生的老师是:<br />'# 遍历所有对象for q in teacher_list:res += str(q.id) + "." + q.name + " <br />"# 反向查询:通过老师,查询对应学生teacher = Teacher.objects.get(id=1)student_list = teacher.student.all()res += '反向查询:老师对应的所有学生是:<br />'# 遍历所有对象for q in student_list:res += str(q.id) + "." + q.name + " <br />"return HttpResponse(res)
注:以上所有添加的方法,都要在 score/urls.py中添加上,否则页面无法访问
程序猿与投资生活实录已改名为 程序猿知秋,WX 公众号同款,欢迎关注!!