ORM模型里连接数据库常用方法和QuerySet API
模型.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多查询语句