一对多表的操作

一、关于一对多的认识

一对多的关系是通过外键来建立关系的,这样的两张表也可以叫多对一,一般我们都是从主表开始叫,不会从从表来叫的,所以一般不会叫多对一.

所谓的主表是指不依赖别人的表,从表是会依赖别的表.

常见的案例:主表(班级)-->从表(学生),主表(部门)-->从表(员工)...

二、django中创建一对多的关系模型(班级->学生)

  • 1、创建主表(班级表)

    class ClassModel(models.Model):
        class_name = models.CharField(max_length=100, blank=True, null=True, verbose_name='班级名称')
    
        def __str__(self):
            return self.class_name
    
  • 2、创建一个从表(学生表)

    class StudentModel(models.Model):
        name = models.CharField(max_length=100, verbose_name='学生姓名')
        gender = models.CharField(max_length=2, verbose_name='性别')
        age = models.IntegerField(max_length=100, verbose_name='年龄')
        mobile = models.CharField(max_length=11, verbose_name='手机号码')
        # 创建一个外键关联到班级表
        classs = models.ForeignKey('ClassModel', on_delete=models.CASCADE, null=True, blank=True)
    
        def __str__(self):
            return self.name
    
  • 3、查看表从表结构(默认会创建一个外键_id的字段)

    mysql> desc app01_studentmodel;
    +-----------+--------------+------+-----+---------+----------------+
    | Field     | Type         | Null | Key | Default | Extra          |
    +-----------+--------------+------+-----+---------+----------------+
    | id        | int(11)      | NO   | PRI | NULL    | auto_increment |
    | name      | varchar(100) | NO   |     | NULL    |                |
    | gender    | varchar(2)   | NO   |     | NULL    |                |
    | age       | int(11)      | NO   |     | NULL    |                |
    | mobile    | varchar(11)  | NO   |     | NULL    |                |
    | classs_id | int(11)      | YES  | MUL | NULL    |                |
    +-----------+--------------+------+-----+---------+----------------+
    6 rows in set (0.00 sec)
    
    mysql>
    

三、关于外键中删除的指定(django2.0+后必须要加的)

  • CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
  • PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误。
  • SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。
  • SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
  • SET():自定义一个值,该值当然只能是对应的实体了

四、关于一对多新增数据

  • 1、必须先要新增主表数据

    def test(request):
        ClassModel.objects.create(class_name='1班')
        ClassModel.objects.create(class_name='2班')
        ClassModel.objects.create(class_name='3班')
        ClassModel.objects.create(class_name='3班')
        return HttpResponse('ok')
    
  • 2、新增学生数据(方法一:使用classs模型)

    classModel = ClassModel.objects.get(pk=1)
        # 学生模型中创建外键关联的classs是一个数据模型
        StudentModel.objects.create(name='张三', gender='男', age=20, mobile='110', classs=classModel)
        return HttpResponse('ok')
    
  • 3、新增学生数据(方法二:直接使用classs_id)

    def test(request):
        classModel = ClassModel.objects.get(pk=1)
        StudentModel.objects.create(name='李四', gender='男', age=20, mobile='110', classs_id=classModel.id)
        return HttpResponse('ok')
    

五、关于一对多的查询数据

  • 1、关于正面查找(从表查询主表数据),直接使用从表中定义的数据模型字段

    def test(request):
        student = StudentModel.objects.get(pk=1)
        print(student.classs.class_name)
        return HttpResponse('ok')
    
  • 2、关于反向查找(主表查询从表数据)

    def test(request):
        classsResult = ClassModel.objects.get(pk=1)
        re = StudentModel.objects.filter(classs=classsResult).values('name', 'age', 'gender')
        print(re)
        return HttpResponse('ok')
    
  • 3、关于反向查找(主表会默认创建一个从表model小写_set的字段)

    def test(request):
        classsResult = ClassModel.objects.get(pk=1)
        re = classsResult.studentmodel_set.all()
        print(re)
        return HttpResponse('ok')
    
  • 4、关于反向查找(关于第三点中的自定义别名)

    • 1.在外键关联的时候就创建一个别名(aaaa)

      classs = models.ForeignKey('ClassModel', on_delete=models.CASCADE, null=True, blank=True, related_name='aaaa')
      
    • 2.反向查找的时候主表中可以直接使用别名

      def test(request):
          classsResult = ClassModel.objects.get(pk=2)
          re = classsResult.aaaa.all()
          print(re)
          return HttpResponse('ok')
      
  • 5、使用双下划线进行跨表查询主表信息

    def test(request):
        student = StudentModel.objects.all().values('name', 'age', 'gender', 'classs__class_name', 'classs_id')
        print(student)
        return HttpResponse('ok')
    

六、关于父子孙这样的外键关联的使用

  • 1、业务场景:学生-->班级-->学校的关系

    class ClassModel(models.Model):
        class_name = models.CharField(max_length=100, blank=True, null=True, verbose_name='班级名称')
        school_name = models.ForeignKey('School', on_delete=models.SET_NULL, null=True, blank=True, related_name='bbbb')
    
        def __str__(self):
            return self.class_name
    
  • 2、关于正向查询

    def test(request):
        student = StudentModel.objects.filter(name='张三').values('name', 'age', 'gender', 'classs__class_name', 'classs__school_name__school_name')
        print(student)
        return HttpResponse('ok')
    

七、总结

  • 1、在一对多的关系表创建过程中,注意区分谁是主表(主表什么都不做),谁是从表(在从表中添加ForeignKey外键关联)
  • 2、关于正向查找与反向查找的问题,从表查询主表是正向查询,主表查询从表是反向查询,一般我们开发过程中尽量使用正向查询,少使用反向查询,但是我们也要知道所谓的反向查询
  • 3、django2.0+后创建外键关联的时候要创建删除方式(请参考第三点)

results matching ""

    No results matching ""