Model关联模型,一对一,一对多,多对多

发布时间 2023-09-09 08:35:58作者: 烧香

一、一对一关系

1、我们在models中创建一个新的模型,叫做StudentInfo

点击查看代码
class StudentInfo(BaseModel):
    """学生信息附加表"""
    address = models.CharField(max_length=255,verbose_name="家庭地址")
    # 当设置字段为外键时,ORM会自动根据当前外键属性名拼接上_id作为数据表中的字段名
    # 例如,外键为student,则数据表中的真是字段名为student_id
    student = models.OneToOneField(Student,related_name="info",on_delete=models.DO_NOTHING,verbose_name="外键")
​
    class Meta:
        db_table = 'db_student_info'
        verbose_name = "学生信息附加表"
        verbose_name_plural = verbose_name
​
    # 3.模型操作方法
    def __str__(self):
        return f'<UserInfo {self.student.name}>'

2、在视图中创建一个新的类,RelationView,记得去绑定路由

点击查看代码
from .models import StudentInfo
class RelationView(View):
    """关联查询:通过表与表之间的关系进行数据库连接,这个在ORM中叫关联查询"""
    def get(self,request):
        """
        1.一对一关系:主表中的一条记录,在从表中只对应最多一条记录,同理,附加表中的一条记录最多对应主表中的一条记录
        用户表和用户附加表,商品表和商品详情表......
        """
​
        # 添加测试数据
        # 1.直接从数据库层面设置id的数值
        # student_info = StudentInfo.objects.create(student_id=2,address="北京市中心广场")
        # print(student_info)
​
        # 2.直接按主模型添加
        # student = Student.objects.get(pk=5)
        # student_info = StudentInfo.objects.create(student=student,address = "北京市")
        # print(student_info)
​
        """关联查询"""
        # 正向查询,从Student---->StudentInfo方向查询
        # student = Student.objects.get(pk=2)
        # # 在外键中声明了related_name的情况下使用related_name的值可以直接获取外键对象
        # print(student.info)
        # print(student.info.address)
​
        # 逆向查询,从StudentInfo--->Student方向
        # student_info = StudentInfo.objects.get(pk=2)
        # print(student_info.student.name)
​
        """更新和删除"""
        # 先获取主模型,然后从主模型中获取附加模型对象,通过附加模型对象修改数据
        # student = Student.objects.get(pk=2)
        # print(student.info.address)
        # # 修改操作
        # student.info.address = "山西省"
        # student.info.save()
        # student = Student.objects.get(pk=2)
        # print(student.info.address)
​
        # 先获取附加模型,然后通过附加模型获取主模型对象,通过主模型对象修改数据
        # student_info = StudentInfo.objects.get(pk=2)
        # print(student_info.student.age)
        # student_info.student.age = 20
        # student_info.student.save()
        # print(student_info.student.age)
​
        """删除操作"""
        # 先删外键对应的记录,然后删除主键对应的记录
        # student_info = StudentInfo.objects.filter(student_id=2).first() # on_delete=Do_NOTHING
        # student_info.delete()
        # student = Student.objects.get(pk=4)
        # student.delete()
​
        return HttpResponse("ok")

二、一对多关系

3、我们再创建一个模型

点击查看代码
class Achievement(BaseModel):
    """成绩表"""
    # ForeignKey 一对多
    student = models.ForeignKey(Student,related_name="score_list",on_delete=models.DO_NOTHING,verbose_name="外键",null=True)
    # max_digits 总数值长度,不包含小数点
    # decimal_places 小数位数的字符最多允许有几个
    score = models.DecimalField(max_digits=5,decimal_places=2,verbose_name="成绩")
​
    class Meta:
        db_table = 'db_student_achievement'
        verbose_name = "学生成绩表"
        verbose_name_plural = verbose_name
​
    # 3.模型操作方法
    def __str__(self):
        return f'<UserInfo {self.student.name}>'

4、在视图中写一个视图

点击查看代码
from .models import Achievement
class RelationView(View):
    def get(self,request):
        """
        1对多:主表的一条记录,在表中只对应一条或多条记录,同理,附加表中的一条记录最多对应主表中的一条记录
        表达的是业务中的一种从属关系
        用户表和用户附加信息表,商品表和商品详情表,文章表和文章详情表
        """
        """添加数据"""
        # student = Student.objects.get(pk=2)
        # print(student.score_list)   # 等同于 Achievement.objects
        # print(student.score_list.all())   # 等同于 Achievement.objects.filter(student_id=2).all()
        # student.score_list.create(student=student,score=66)
​
        """查询数据"""
        # 正向查找
        # student = Student.objects.get(pk=2)
        # score_list = student.score_list.values()
        # print(score_list)
​
        # 不设置related_name,可以基于"外键模型小写_set"来获取外键模型
        # student = Student.objects.get(pk=2)
        # score_list = student.achievement_set.values()
        # print(score_list)
​
        # 反向查找
        # achi = Achievement.objects.get(pk=3)
        # print(achi.student)
        # print(achi.score)
​
        """更新和删除数据,它们只能通过模型来完成"""
        # 删除
        # student = Student.objects.get(pk=2)
        # score_list = student.score_list.all()
        # for score in score_list:
        #     score.delete()
​
        # 更新
        # student = Student.objects.get(pk=2)
        # # 遍历或者下标操作都可以
        # score_list = student.score_list.first()
        # score_list.score = 20
        # score_list.save()
        return HttpResponse("ok")

三、多对多关系

5、我们再在模型中创建两个模型

点击查看代码
class Teacher(models.Model):
    name = models.CharField(max_length=15,verbose_name="老师")
​
    class Meta:
        db_table = "db_teacher"
        verbose_name = "老师信息表"
        verbose_name_plural = verbose_name
​
class Course(models.Model):
    name = models.CharField(max_length=15,verbose_name="课程")
    # 多对多,外键不需要设置on_delete属性
    # 老师授课的课程:teacher.course_list
    # 课程授课的老师:course.teacher_list
    teacher_list = models.ManyToManyField(Teacher,related_name = "course_list")
​
    class Meta:
        db_table = "db_course"
        verbose_name = "课程信息表"
        verbose_name_plural = verbose_name

6、在视图中创建一个视图

点击查看代码
from .model import Course,Teacher
class RelationView(View):
    def get(self,request):
        """
        范式理论:
        第一范式:不能有重复的属性
        第二范式:必须唯一
        第三范式:不能冗余
​
        多对多:A表中的一条记录,在B表中有对应的信息表,反之,B表中的一条记录也可以在A表中找到多个对应的记录
        课程和学生的之间关系,好友与好友之间关系,读者和文章之间的关系,购买者和商品之间的关系......
        """
        """添加数据"""
        # teacher1 = Teacher.objects.create(name="龙老师")
        # teacher2 = Teacher.objects.create(name="林老师")
        # teacher3 = Teacher.objects.create(name="李老师")
        # teacher4 = Teacher.objects.create(name="程老师")
        #
        # course1 = Course.objects.create(name="Python初级")
        # course2 = Course.objects.create(name="Python中级")
        # course3 = Course.objects.create(name="Python高级")
​
        # 通过老师添加课程,反过来也是类似
        # teacher = Teacher.objects.get(pk=1)
​
        # 此处不仅可以添加课程,而且我们还可以完成老师和课程之间的绑定
        # teacher.course_list.create(name="javascript入门")
​
        # 添加已存在的课程信息渝老师绑定关系
        # course = Course.objects.get(pk=3)
        # teacher.course_list.add(course)
​
​
        """查找数据"""
        # 查询老师授课的课程
        # teacher = Teacher.objects.filter(name="龙老师").first()
        # print(teacher.course_list.values())
​
        # 查询课程的授课老师都有谁
        # course = Course.objects.get(pk=3)
        # print(course.teacher_list.values())
​
        """更新删除数据"""
        # 当希望删除两个模型之间的一条关联关系时,我们使用remove
        # course = Course.objects.get(pk=3)
        # teacher = Teacher.objects.filter(name="龙老师").first()
        # course.teacher_list.remove(teacher)
​
        # 当希望删除两个模型之间的全部关联关系时,我们使用clear
​
        # 删除对应模型的单个模型就调用单个模型对象来完成
​
        return HttpResponse("ok")

7、创建一个新的模型:

点击查看代码
class Area(models.Model):
    """行政区划"""
    name = models.CharField(max_length=20)
    parent = models.ForeignKey("self",related_name="son_list",null=True,on_delete=models.DO_NOTHING)
​
    class Meta:
        db_table = "db_area"
        verbose_name = "行政区划表"
        verbose_name_plural = verbose_name
​
    def __str__(self):
        return f'<UserInfo {self.student.name}>'

8、创建一个新视图,请自行尝试

点击查看代码
from .models import Area
class RelationView(View):
    def get(self,request):
        """自关联"""
        # 查询顶级单位
        province_list = Area.objects.filter(parent_id__isnull=True).all()
        print(province_list)
        province = province_list.filter(name="河南省").first()
        print(province)
        city_list = province.son_list.all()
        print(city_list)
        city = city_list.filter(name="郑州市").first()
        print(city)
        area_list = city.son_list.all()
        print(area_list)
        area = area_list[0]
        print(area)
        return HttpResponse("ok")