12月15日学习内容整理:ORM中的queryset类型,中介模型,extra函数和分组补充

一、queryset类型:只和ORM有关

1、切片

支持索引切片,但不支持负数索引(不能用-1代表最后一个元素)

2、是可迭代的

3、属于惰性查询

我们构建出一个queryset类型,比如obj=Book.objects.all(),如果我们不去调用这个obj,不去使用它,ORM是不会查询数据库的,一旦我们使用了obj,ORM才会从数据库中提取数据,也就是我们对obj进行操作的时候(即对记录进行操作时)才会走数据库,只单单定义这个obj,ORM是不会走数据库的

4、缓存机制

queryset会有自己的缓存来存放从数据库查询的结果,后续在对这个数据进行访问就从缓存里提取,不会再查询数据库

但是这里有一个问题,若我们在中间插入或者修改记录,这个结果是不会更新到缓存中的,我们再对数据进行访问还是取到原来的数据,所以我们只能再次查询生成新的queryset

查询集不会永远缓存它们的结果。当只对查询集的部分进行求值时会检查缓存, 如果这个部分不在缓存中,那么接下来查询返回的记录都将不会被缓存。所以,这意味着使用切片或索引来限制查询集将不会填充缓存。

缓存机制最根本的优势在于减少了对数据库的查询次数

5、优化缓存

queryset的缓存机制有一个很大的问题,那就是当数据库中的记录的数量很庞大时,我们调用queryset时会把所有的数据一并灌入内存中,这是很危险的,所以我们只能一条或几条的去取,由此就想到了迭代器

(1)exists方法:查询数据存不存在,只查询到一条就返回true

(2)queryset对象.iterator()   这就把一个queryset类型变成了一个迭代器,我们可以遍历取值,避免了庞大数据同时占据内存

总的来说::::::

queryset的缓存是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能会造成额外的数据库查询。

 

 

二、中介模型

1、应用场景:

在跨表的多对多关系中,ORM会为我们自动创建第三张表来专门记录两张表的多对多关系,但某种情况下我们可能需要在这个第三张关系表中添加新的字段,这种需需求显然Manytomanyfield已经不能满足,他无法为我们添加新的字段,所以就用到了中介模型

2、使用

显然我们要自己创建第三张关系表,和两张表分别做foreignkey,那这样的话我们查询时就会非常繁琐,因为两张表中已经没有关联字段了,这就是中介模型解决的问题

class Student(models.Model):
    sname=models.CharField(max_length=20)
    age=models.IntegerField()

class Course(models.Model):
    cname=models.CharField(max_length=20)
    students = models.ManyToManyField("Student", through="Score")
class Score(models.Model):
    student=models.ForeignKey("Student")
    course=models.ForeignKey("Course")
    score=models.IntegerField()

我们在models里构建以上三个表,学生和课程是多对多关系,Score是我们自己创建的关系表,分别与学生表和课程表做关联,并且添加一个新的字段score,在学生表或课程表中依然创建关联字段students= models.ManyToManyField("Student", through="Score"),利用through参数就可以利用这个关联字段做查询了

表名=models.ManyToManyField(另一张表名,through=第三张关系表名(也就是我们自己创建的))

 

注意注意注意:::利用中介模型,我们对第三张表插入记录时就只能自己实例化了,因为add没法添加新的字段值

 

 

三、extra函数

1、应用场景:

ORM无法简单的表达sql中复杂的查询where语句,所以就用到了extra函数,用来实现在ORM生成的sql语句中注入新的sql原生语句

2、使用

(1)select参数

》》》先补充:

》》》mysql函数:date_format(表的字段名,"%Y-%m-%d")  一般用于日期类型,是为了截取数据中的年月日信息

》》》ORM自带的sqlite函数:strftime("%%Y-%%m-%%d",字段名)    和上面的函数是一样的效果,都是截取年月日信息

queryset类型调用.extra(select={key:"strftime("%%Y-%%m-%%d",字段名)"})   可以写多个key多个value值,value就可以写原生sql语句,比如举例的这种,会把日期中的年月日提取出来作为value值;还可以写诸如sql中"price>100"这样的判断语句,满足就返回1不满足就返回0,1或者0就是value值

返回queryset类型

实现的功能:给调用的queryset类型中的每一个model对象添加名为key的字段,value值就是sql语句生成的内容

 

 

四、分组补充

1、之前我们讲的是:

Book.objects.all().annotate()    这样就是把前面queryset类型中的每一个model对象作为一组,分组依据是所有的字段,再利用聚合函数进行分组统计

2、怎么能把某一个字段作为分组依据呢

Book.objects.all().extra(select={key:value}).values("key").annotate()    前面如果出现了values或者values_list,就把其中的key作为分组依据,再利用聚合函数进行分组统计

 

posted @ 2017-12-15 14:58  九二零  阅读(245)  评论(0编辑  收藏  举报