Python(Web时代)—— Django数据库(多表)

两表联查

常见的两表关系:

一对多:ForeignKey 

  • 举例:一个学生对应多个地址

  • 一般通过外键实现

  • 需要在“多”的那个模型中使用ForeignKey

  • 使用on_delete指定级联删除策略:

    • CASCADE:当父表数据删除时,相对应的从表数据会被自动删除

    • SET_NULL:当父表数据删除时,相对应的从表数据会被自动设置为null值

    • PROTECT:当父表数据删除时,如果有相对应的从表数据会抛出异常

    • SET_DEFAULT: 当父表数据删除时,相对应的从表数据会被自动设置为默认值,还需要额外指定default=True

一对一:OneToOneField

  • 举例:一个人对应一个身份证号

  • 数据字段设置 unique

  • 可以在任何一个模型类使用OneToOneField

多对多:ManyToManyField

  • 举例:一个学生有多个老师,一个老师有多个学生

    扫描二维码关注公众号,回复: 17234426 查看本文章
  • 一般通过第三个表来实现关联

  • 可以在任何一个模型类使用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方法直接生成数据,不需要再去调用save
    student = Student.objects.create(name='王老五', age=10,create_time=timezone.now())
    # 增加地址,通过外键_id形式给外键赋值 id
    Address.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.name
    res +=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.num
    res='正向查询:该学生所有的身份id是:<br />'+idcard_num+"<br />"

    # 反向查询:通过身份,查询对应学生
    idcard = Idcard.objects.get(id=2)
    student_name = idcard.student.name
    res +='反向查询:身份对应的学生是:<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 公众号同款,欢迎关注!! 

猜你喜欢

转载自blog.csdn.net/qq_25702235/article/details/132587382
今日推荐