ORM模型里连接数据库常用方法和QuerySet API

时间:2022-05-08 02:54:15

模型.objects:

这个对象是django.db.models.manager.Manager的对象,这个类是一个空壳类,他上面的所有方法都是从‘QuerySet‘这个类上面拷贝过来的。因此我们只要学会了‘QuerySet‘,这个‘objects’也就知道如何使用了。

‘Manage‘源码解析:

、、、python

class_name = BaseManagerFromQuerySet


Class_dict = {
    _queryset_class:QuerySet      
}


Class_dict.update(cls.get_queryset_methods(QuerySet))

#type动态的时候创建类

#第一个参数是用来指定创建的类的名字。 创建的类名是:BaseManagerFromQuerySet

#第二个参数是用来指定这个类的父类。

#第三个参数是用来指定这个类的一些属性和方法

return type(class_name,(cls,),class_dict)

 

 

_get_query_methods:这个方法就是将Queryset中的一些方法拷贝出来

 

##filter/exclude.annotate:过滤/排除满足条件的/给模型添加新的字段。

 

##order_by:

#根据创建的时间正序排序
articles = Article.objects.order_by("create_time")
# 根据创建的时间倒序排序
articles = Article.objects.order_by("-create_time")
# 根据作者的名字进行排序
articles = Article.objects.order_by("author__name")
# 首先根据创建的时间进行排序,如果时间相同,则根据作者的名字进行排序
articles = Article.objects.order_by("create_time",author__name)

一定要注意的是,多个‘order_by’,会把前面排序的规则给打乱,而使用后面的排序方式。如:

articles = Article.objects.order_by("create_time").order_by("author__name")

 

它会根据作者的名字进行排序,而不是使用文章的创建时间。

当然,也可以在模型定义的在‘Meta’类中定义‘ordering‘来指定默认的排序方式。如

    class Meta:
        db_table = book_order
        ordering = [create_time,-price]

 

还可以根据`annotate`定义的字段进行排序。比如要实现图书的销量进行排序,那么示例代码如下:

books = Book.objects.annotate(order_nums=Count("bookorder")).order_by("-order_nums")
    for book in books:
        print(%s/%s%(book.name,book.order_nums))

 

values:

有时候我们在表中查找数据的时候,并不是想要把所有的字段都提取出来,
有可能只想要其中的几个字段,这时候就可以使用`values`来实现,需要什么字段,就把这个字段的名字传到这个方法中

books = Book.object.values(id,‘name)

`values`的返回值同样也是一个`QuerySet`对象,但是里面装的不再是模型,而是字典

如果我们想要提取的使者模型上关联的对象的属性,也是可以的,查找方法跟`filter`的用法是一样的

books=Book.object.values(id,name,author__name)


以上会提取`author`的`name`字段,如果想要更改这个默认的名字那么可以使用关键字参数

books=Book.objects.values(id,name,author_name=F(author__name))

 

自定义的名字,不能和模型上本身拥有的字段一样,比如以上‘author_name’如果取名叫做‘author‘就会报错,因为“Book‘表里本身就拥有一个字段叫做’author‘

在’vialues‘中,也可以使用聚合函数来形成一个新的字段,比如想要获取每本书的销量

books=Book.objects.values(id,name,order_nums=Count(bookorder))

如果调用‘values‘方法的时候,没有传递任何的参数,name会获取这个模型上的所有字段以及对应的值形成的字典

books=Book.objects.values
#bookS值如下:
###{‘id‘:1,‘name‘:‘三国演义‘,‘pages‘:987,‘price‘:108,rating:3.9,‘author_id‘:3,‘publisher_id‘:1}

 

values_list

跟value是一样的作用,只不过这个方法返回的是’QuerySet‘中,装的不是字典而是元组

books = Book.objects.values_list(id,name)

##结果是:(1,’三国演义‘)

 如果给`values_list`只指定一个字段,那么可以指定`flat=True`这样返回的结果就不在是一个元组,而是这个字段的值

books=Book.objects.values_list(name,flat=True)

###结果是 ‘三国演义‘

flat只能用在只有一个字段的情况下,否则会报错

 

all方法

这个返回简单的一个`QuerySet`对象,这个对象没有经过任何修改(比如:过滤等)

 

## select_related

在查找某个表的数据的时候,可以一次性把相关联的其他表的数据都提取出来,这样可以在以后访问相关联的数据的时候,不用再次查找数据库,可以节省一些开销

books=Book.objects.select_related(‘author‘,‘publisher‘)
for book in books: print(book.author.name)d #因为在提取Book的时候,使用了select_related,那么以后再访问book_author的时候,不会再次向数据库重新发起查询了

 注意:


注意:这个方法只能用在外键关联的对象上,对于那种多对多,或者一对多的情况,不能使用它来实现,而应该使用`perfetch_related`来实现

 

prefetch_related:

这个方法类似于select_related方法,也是用在查询语句的时候,提前将指定的数据查找出来,只不过这个方法是是用来解决多对多或者多对一的情况,这个方法会产生两个查询语句,所以,如果在这个方法中查询使用外键关联的模型的时候,也会产生两个查询语句,因此如果查询的是外键关联的模型,建议使用`select_related`方法。在查询多对多或者多对一的关联的队形的时候,在使用模型怎么访问这个多对多,就在这方法中传递什么字符串,比如要获取图书上的所有订单,代码如下

books=Book.objects.prefetch_related(bookorder_set)

需要注意的是:在使用`prefetch_related`查找出来的`bookorder_set`建议不要在对它进行任何操作,比如`filter`,不然又会产生N多查询语句