Django模型系统——ORM表结构对应关系

对于数据库来说一般表结构只会有三种对应关系,分别是一对一、一对多和多对一,下面分别介绍:

1.一对多

何为一对多,例如一个学生只可能有一个班级,一个班级却又多个学生,班级表和学生表就是一对多的关系。

在查询信息的时候有两种方式:正向查询和反向查询。

(1)正向查询

复制代码
models.Student.objects.first()
<Student: Student object>#返回一个学生对象
models.Student.objects.first().sname  #可以查询学生信息
'科比'
models.Student.objects.first().cid  #由于有关联,可以直接获取班级对象
<Class: Class object>
models.Student.objects.first().cid.cname  #查询班级属性
'全栈6期'
models.Student.objects.first().cid.first_day
datetime.date(2017, 7, 14)
复制代码

 

(2)反向查询

复制代码
models.Class.objects.filter(id=3)
<QuerySet [<Class: Class object>]>
#这是一个班级Queryset

models.Class.objects.filter(id=3)[0]
<Class: Class object>
#获取班级对象

models.Class.objects.filter(id=3)[0].cname
'全栈8期'
#既然是对象就可以查看相关属性

models.Class.objects.filter(id=3)[0].student_set
<django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x0000019A6A928FD0>
#反向查找学生,获取学生集合,这是Django自己的模式

models.Class.objects.filter(id=3)[0].student_set.all()
<QuerySet [<Student: Student object>, <Student: Student object>]>
#查看集合中所有的对象

models.Class.objects.filter(id=3)[0].student_set.all().values()
<QuerySet [{'id': 8, 'sname': '小鸟', 'cid_id': 3}, {'id': 11, 'sname': '大爷', 'cid_id': 3}]>
#可以进一步查看相关属性
复制代码

注意:

如果不在外键的字段中设置related_name的话,默认就用表名_set.

如果设置了related_name=“students”,反向查找时可以直接使用student进行反向查找。

>>> class_obj.students.all() 
#直接获取班级中的学生,而不需要set

 

2.一对一

表结构设计

复制代码
class Student(models.Model):
    id = models.AutoField(primary_key=True)
    sname = models.CharField(max_length=32)
    cid = models.ForeignKey("Class")
    detail = models.OneToOneField(to="StudentInfo", null=True)

class StudentInfo(models.Model):
    height = models.CharField(max_length=4)
    weight = models.CharField(max_length=4)
    addr = models.CharField(max_length=32,null=True)
复制代码

(1)正向查询

复制代码
models.Student.objects.first()
<Student: Student object>
#获得一个对象

models.Student.objects.first().detail.addr
'罗田'
#正向查询获取属性,通过关联字段直接找
复制代码

 

(2)反向查询

复制代码
models.StudentInfo.objects.filter(height=180)
<QuerySet [<StudentInfo: StudentInfo object>]>
#获得一个Queryset

models.StudentInfo.objects.filter(height=180)[0].student
<Student: Student object>
#反向查找学生,返回一个对象

models.StudentInfo.objects.filter(height=180)[0].student.sname
'小鸟'
#查看学生信息
复制代码

 

3.多对多

1)创建多对多的对应关系有三种方法:

(1)通过外键创建

复制代码
class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主键
    cname = models.CharField(max_length=32)  # 班级名称
    first_day = models.DateField()  # 开班时间


class Teacher(models.Model):
    tname = models.CharField(max_length=32)


# 自定义第三张表,通过外键关联上面两张表
class Teacher2Class(models.Model):
    teacher = models.ForeignKey(to="Teacher")
    the_class = models.ForeignKey(to="Class")

    class Meta:
        unique_together = ("teacher", "the_class")  #指定联合唯一
复制代码

(2)通过ManyToManyField创建

复制代码
class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主键
    cname = models.CharField(max_length=32)  # 班级名称
    first_day = models.DateField()  # 开班时间


class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    # 通过ManyToManyField自动创建第三张表
    cid = models.ManyToManyField(to="Class", related_name="teachers")
复制代码

这种方法会自动生成一张对应表,但是不能使用多对多的众多方法。

 

(3)通过外键和ManyToManyField创建

复制代码
class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主键
    cname = models.CharField(max_length=32)  # 班级名称
    first_day = models.DateField()  # 开班时间


class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    # 通过ManyToManyField和手动创建第三张表
    cid = models.ManyToManyField(to="Class", through="Teacher2Class", through_fields=("teacher", "the_class"))


class Teacher2Class(models.Model):
    teacher = models.ForeignKey(to="Teacher")
    the_class = models.ForeignKey(to="Class")

    class Meta:
        unique_together = ("teacher", "the_class")
复制代码

貌似这种方法最为靠谱,但是最麻烦。

 

2)查询的方法

(1)正向查询(由老师表查询班级)

复制代码
models.Teacher.objects.first()
<Teacher: Teacher object>
#获取一个老师的对象

models.Teacher.objects.first().cid
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x000001FE3916A518>
#获取老师所对应的班级

models.Teacher.objects.first().cid.all()
<QuerySet [<Class: Class object>, <Class: Class object>]>
#获取所有班级对象

models.Teacher.objects.first().cid.all().values()
<QuerySet [{'id': 1, 'cname': '全栈6期', 'first_day': 
datetime.date(2017, 7, 14)}, {'id': 3, 'cname': '全栈8期', 'first_day': datetime.date(2017, 10, 17)}]>
#查看所有值
复制代码

为什么能够直接找到班级?

答案是:通过关联字段

 

(2)反向查询(由班级表反向查询老师表)

复制代码
models.Class.objects.first()
<Class: Class object>
#获取班级对象

models.Class.objects.first().teachers
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x000001FE3918C390>

models.Class.objects.first().teachers.all().values()
<QuerySet [{'id': 1, 'tname': '爱根'}, {'id': 4, 'tname': '日天'}, {'id': 6, 'tname': '银角大王'}]>
#由班级反向查老师

models.Class.objects.first().teachers.all()
<QuerySet [<Teacher: Teacher object>, <Teacher: Teacher object>, <Teacher: Teacher object>]>
复制代码

刚才正向查找的时候,是因为老师表种由cid这个字段,所以可以直接查找,但是现在这个是怎么关联上的了?请看下面

cid = models.ManyToManyField(to="Class", related_name="teachers")

关联的时候设置了related_name,所以可以反向查找。

注意:这里不能使用teacher_set这种方式,而在一对多种可以使用

来看看各种对应关系的正向查找:

复制代码
#一对多正向查找(学生表——》班级表)
models.Student.objects.first().cid

#一对一正向查找(学生表——》学生信息表)
models.Student.objects.first().detail.addr


#多对多正向查找(老师表到班级表)
models.Teacher.objects.first().cid.all()

#正向查找是表中必须有的字段
复制代码

来看看各种对应关系的反向查找:

反向查找是相对于正向查找来说的。

#一对多反向查找(班级表——》学生表)
models.Class.objects.filter(id=3)[0].student_set.all()

#一对一反向查找(后面直接可查属性)(学生信息表——》学生表)
models.StudentInfo.objects.filter(height=180)[0].student

#多对多反向查找(班级表——》老师表)
models.Class.objects.first().teachers.all()

 

posted @ 2018-01-25 00:04  明王不动心  阅读(623)  评论(0编辑  收藏  举报