一,ORM表和表之间的关系字段
1.一对一:OneToOneField,
通常一对一字段用来扩展已有的字段
Q:为什么要有OneToOneField?
1.当一张表里的字段非常多,并且某几个字段的查询频率远远大于其他字段的时候
2.把常用字段单独拆成一张表,查询的时候更快捷
#示例:作者信息扩展 class Author(models.Model): name = models.CharField(max_length=32) info = models.OneToOneField(to='AuthorInfo') class AuthorInfo(models.Model): phone = models.CharField(max_length=11) email = models.EmailField()
#OneToOneField字段参数 to #设置要关联的表 to_field #设置要关联的字段 on_delete #当删除关联表中的数据是,当前表其关联的行的行为,用法同ForeignKey字段
2.一对多:外键(ForeignKey)
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在'一对多'中‘多’的一方
ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系
#ForeignKey字段参数 to #设置要关联的表 to_field #设置高关联的表的字段 related_name #反向操作时,使用的字段名,用于代替原反向查询时的'表名_set' #例如: class Classes(models.Model): name = models.CharField(max_length=32) class Student(models.Model): name = models.CharField(max_length=32) theclass = models.ForeignKey(to="Classes") #当我们要查询某个班级关联的所有学生(反向查询) Classes.objects.first().student_set.all() #当我们在ForeignKey字段中添加了参数 related_name 后 class Student(models.Model): name = models.CharField(max_length=32) theclass = models.ForeignKey(to="Classes", related_name="students") #然后,当我们要查询某个班级关联的所有学生(反向查询) Classes.objects.first().students.all() related_query_name #反向查询操作时,使用的连接前缀,用于替换表名 on_delete #当删除关联表中的数据时,当前表与其关联的行的行为 on_delete=models.CASCADE #删除关联数据,与之关联也删除 on_delete=models.DO_NOTHING #删除关联数据,引发错误IntegrityError on_delete=models.PROTECT #删除关联数据,引发错误ProtectedError on_delete=models.SET_NULL #删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) on_delete=models.SET_DEFAULT #删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) on_delete=models.SET #删除关联数据, a.与之关联的值设置为指定值,设置:models.SET(值) b.与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象) def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id", on_delete=models.SET(func) ) db_constraint #是否在数据库中创建外键约束,默认为True
3.多对多:另外一种关系表(ManyToManyField)
用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系
#ManyToManyField字段参数 to #设置要关联的表 related_name #反向操作时,使用的字段名,用于代替原反向查询时的'表名_set',用法同ForeignKey字段 related_query_name #反向查询操作时,使用的连接前缀,用于替换表名,用法同ForeignKey字段 symmetrical #仅用于多对多自关联时,指定内部是否创建反向操作的字段,默认为True #例: #此时,person对象就没有person_set属性 class Person(models.Model): name = models.CharField(max_length=16) friends = models.ManyToManyField("self") #此时,person对象现在就可以使用person_set属性进行反向查询 class Person(models.Model): name = models.CharField(max_length=16) friends = models.ManyToManyField("self", symmetrical=False) through #在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过through来指定第三张表的表名 through_fields #通过through_fields来指定第三张表的关联的字段 db_table #默认创建第三张表时,数据库中表的名称
多对多关联关系的三种方式
1.自己创建第三张关系表,外键分别关联两个表
优点:可以扩充第三张关系表的字段
缺点:自己做连表查询
class Book(models.Model): title = models.CharField(max_length=32, verbose_name="书名") class Author(models.Model): name = models.CharField(max_length=32, verbose_name="作者姓名") # 自己创建第三张表,分别通过外键关联书和作者 class Author2Book(models.Model): author = models.ForeignKey(to="Author") book = models.ForeignKey(to="Book") #设置这两个字段联合唯一 class Meta: unique_together = ("author", "book")
2.通过ORM内置的ManyToManyField,自动创建第三张关系表
优点:提供了很多连表操作的快捷方法:all(),add(),set(),clear(),remove()
缺点:无法扩展第三张关系表
class Book(models.Model): title = models.CharField(max_length=32, verbose_name="书名") # 通过ORM自带的ManyToManyField自动创建第三张表 class Author(models.Model): name = models.CharField(max_length=32, verbose_name="作者姓名") books = models.ManyToManyField(to="Book", related_name="authors"
3.自己创建第三张关系表,通过ManyToManyField
优点:既能够使用多对多查询的快捷方法all(),还能够自己扩展第三张关系表的字段
class Book(models.Model): title = models.CharField(max_length=32, verbose_name="书名") # 自己创建第三张表,并通过ManyToManyField指定关联 class Author(models.Model): name = models.CharField(max_length=32, verbose_name="作者姓名") books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book")) # through_fields接受一个2元组('field1','field2'): # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。 class Author2Book(models.Model): author = models.ForeignKey(to="Author") book = models.ForeignKey(to="Book") #设置这两个字段联合唯一 class Meta: unique_together = ("author", "book")
Q.以后该用哪种?
1.当第三张关系表中不需要其他额外字段的时候,我们就用默认的ManyToManyField就可以了
2.当第三张关系表中需要额外的字段时,我们就要用第三种方式,自己建立第三张关系表并使用ManyToManyField
二,ORM关联查询
1.基于对象的查询(跨表)
1.正向查询
语法:对象.关联字段.字段
#示例: book_obj = models.Book.objects.first() # 第一本书对象 print(book_obj.publisher) # 得到这本书关联的出版社对象 print(book_obj.publisher.name) # 得到出版社对象的名称
2.反向查询
语法:obj.表名_set
1.默认不设置related_name属性
1.查找的对象是多个的时候(一对多或多对多时)
语法:publisher_obj.book_set.all()
2.查找的对象是一个的时候(一对一)
语法:author_info_obj.author.name
2.设置related_name='books'属性
publisher_obj.books.all()
#示例 publisher_obj = models.Publisher.objects.first() # 找到第一个出版社对象 books = publisher_obj.book_set.all() # 找到第一个出版社出版的所有书 titles = books.values_list("title") # 找到第一个出版社出版的所有书的书名
2.基于QuerySet的查询
1.正向查询
语法:关联字段__字段
#示例 Book.objects.filter(id=1).values_list('publisher_name') Book.objects.values_list("publisher__name") #查询全部的时候all()可省略
2.反向查询
语法:表名__字段
1.默认不设置related_name属性,默认就用类名的小写
Publisher.objects.filter(id=1).values_list('book_price')
2.设置related_name='book'属性
Publisher.objects.filter(id=1).values_list('books_price')
titles = Publisher.objects.values_list("book__title")