zoukankan      html  css  js  c++  java
  • QuerySetAPI笔记

    学习Django时做的笔记MarkDown文件点这里

    # 模型.objects:
    这个对象是`django.db.models.manager.Manager`的对象,这个类是一个空壳类,他上面的所有方法都是从`QuerySet`这个类上面拷贝过来的。因此我们只要学会了`QuerySet`,这个`objects`也就知道该如何使用了。
    `Manager`源码解析:
    ```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_queryset_methods:这个方法就是将QuerySet中的一些方法拷贝出来
    ```

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

    # order_by:
    ```python
    # 根据创建的时间正序排序
    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`,会把前面排序的规则给打乱,而使用后面的排序方式。比如以下代码:

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

    他会根据作者的名字进行排序,而不是使用文章的创建时间。
    当然,也可以在模型定义的在`Meta`类中定义`ordering`来指定默认的排序方式。示例代码如下:
    ```python
    class Meta:
    db_table = 'book_order'
    ordering = ['create_time','-price']
    ```

    还可以根据`annotate`定义的字段进行排序。比如要实现图书的销量进行排序,那么示例代码如下:
    ```python
    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' 来进行指定,并且使用了 'values' 方法后,提取出
    的 QuerySet 中的数据类型不是模型,而是在 'values' 方法中指定的字段和值形成的字典:

    ```python
    articles = Article.objects.values("title",'content')
    for article in articles:
    print(article)
    ```

    以上打印出来的 'article' 是类似于 `{"title":"abc","content":"xxx"}` 的形式。
    如果在 'values' 中没有传递任何参数,那么将会返回这个恶模型中所有的属性。

    ## 如果我们想要提取的是这个模型上关联的属性,那么也是可以的,查找顺序跟'filter'的用法是一样的,示例代码如下:
    ```python
    books = Book.objects.valuse('id', 'name', author_name=("author__name"))
    ```
    ## 以上将会提取作者的名字字段,如果想要更改一个名字,可以使用关键字参数,示例代码如下:
    ```python
    books = Book.objects.valuse('id', 'name', author_name=F("author__name"))
    ```
    自定义的名字不能和已经存在的名字一样,比如`author_name`不能重复。
    ## 在`values`中可以使用聚合函数来形成一个新的字段,比如想要获取每本书的销量,示例代码如下:
    ```python
    books = Book.objects.values('id', 'name', order_nums=Count("bookorder"))
    ```

    # values_list
    ## 跟`values`是一样的作用,只不过这个方法返回的`QuerySet`中装的不是字典,而是元组,示例如下:
    ```python
    books = Book.objects.values_list('id', 'name')
    ```
    那么以上返回的结果是`(1,'三国演义')`,
    ## 如果给`values_list`只指定一个字段,那么可以指定`flat=True`,这样返回的结果就不是一个元组,而是这个字段的值,示例代码入下:
    ```python
    books = Book.objects.values_list('name', flat=True)
    ```
    ## 注意`flat`只能用在只有一个字段的情况下,否则会报错

    # all方法
    ## 返回一个`QuerySet`对象,没有做任何更改,会返回所有属性,很少用到。

    # select_related方法
    ## 在提取某个模型的数据的同时,也提前将相关联的其他表的数据取出来,在以后访问相关联的的表的数据的时候,不用再次查找,节省开销。
    比如提取文章数据的同时,可以取作者信息表的数据,示例代码如下:
    ```python
    books = Book.objects.select_related("author","publisher")
    for book in books:
    print(book.author.name)
    print(book.publisher.name)
    # 因为在提取Book的时候,使用了select_related,那么以后在访问book.author 的时候,不会再次发起请求。
    ```
    ## 注意:这个方法只能用在外键的关联对象上,对于那种多对多、多对一的情况,不能使用此方法,而应该使用`prefetch_related`来实现。

    # prefetch_related方法
    ## 和`select_related`方法类似,用在处理那种多对多、多对一的情况。
    这个方法会产生两个查询语句,所以,如果在这个方法中查询使用外键关联的模型的时候,也会产生两个查询语句,因此,如果查询的是外键关联的模型,建议使用`select_related`方法。
    在查询多对多关系或者一对多的关联的对象的时候,你在使用模型怎么访问这个多对多,那么久在这个方法中传递什么字符串,比如要获取图书的所有订单,示例代码如下:
    ```python
    books = Book.objects.prefetch_related("bookorder_set")
    ```
    ## 注意:如果在使用`prefetch_related`查找出的`bookorder_set`,建议不要对他进行任何操作,比如`filter`,不然又会产生更多的查询语句,是不对的:
    ```python
    books = Book.objects.prefetch_related("bookorder_set")
    for book in books:
    print('='*30)
    print(book.name)
    orders = book.bookorder_set.filter(price__gte=90)
    for order in orders:
    print(order.id)

    ```
    ## 如果确实想要对预先查找的集合进行操作,那么我们可以使用`models.Prefetch`来完成:
    ```python
    # 先使用prefetch将查询的条件写好,再来使用。
    prefetch = Prefetch("bookorder_set",queryset=BookOrder.objects.filter(price__gte=90))
    books = Book.objects.prefetch_related(prefetch)
    for book in books:
    print('='*30)
    print(book.name)
    orders = book.bookorder_set.all()
    for order in orders:
    print(order.id)
    ```

    # defer 方法
    ## 在一些表中,可能存在很多字段,但是一些字段的数据量可能是比较大的,而你此时又不需要,这个时候可以使用`defer`来过滤掉一些字段(可以是多个),这个字段跟`values`有点类似,只不过`defer`返回的不是字典,而是模型。
    ```python
    books = Book.objects.defer("name")
    ```
    ## 注意: 使用`defer`的字段,以后再次使用的话,会再次发起请求,请谨慎操作。


    # only
    ## 跟`defer`类似,不过`only`是只提取某些字段(可以是多个)。
    ```python
    books = Book.objects.only('name')
    # 默认是提取 'id'的
    ```
    ## 注意: 没有使用`only`的字段,以后想要使用的话,会再次发起请求,请谨慎操作。

    # get 方法
    ## 获取满足条件的数据,这个函数只能返回一条数据,并且如果给的条件有多条数据,那么这个方法会抛出错误,如果给的条件没有任何数据,也会抛出错误,送一这个方法在获取数据的时候,只能有一条数据。
    ```pyhton
    book = Book.objects.get(id=5)
    ```

    # create 方法
    ## 创建一条数据,并且保存到数据库中,这个方法相当于先用指定的模型创建一个对象,然后再调用这个对象的`save`方法,示例如下:
    ```python
    # publisher = Publisher(name='知了出版社')
    # publisher.save()
    publisher = Publisher.objects.create(name='知了课堂出版社')
    ```

    # get_or_create 方法
    ## 根据某个条件进行查找,如果找到就返回这条数据,如果没有找到,那么就创建一个,示例代码如下:
    ```python
    # result = Publisher.objects.get_or_create(name='知了abc出版社')
    # print(result[0])
    ```


    # bulk_create 方法
    ## 一次性创建多个数据,示例代码如下:
    ```
    publisher = Publisher.objects.bulk_create([
    Publisher(name='123出版社'),
    Publisher(name='abc出版社'),
    ])
    ```
    优势在于执行一次,将所有的数据都插入到数据库,效率高。


    # count 方法
    ## 获取提取的数据的个数,如果想要知道总共有多少条数据,那么建议使用`count`,而不是`len(articles)`这种,因为`count`在底层使用`select count(*)`来实现,更加高效。
    ```python
    count = Book.objects.count()
    ```


    # first 和last 方法
    ## 返回`QuerySet`中的第一条和最后一条数据。


    # aggregate 方法
    ## 使用聚合函数。


    # exists 方法
    ## 判断某个条件的数据是否存在,如果要判断某个条件的元素是否存在,那么建议使用`exists`,这比直接使用`count`或者直接判读`QuerySet`更有效,实例代码如下:
    ```python
    result = Book.objects.filter(name='三国演义').exists()
    ```


    # distinct 方法
    ## 去掉那重复的数据,这个方法如果底层数据库用的是MySQL,那么不能传递任何值,比如想要提取所有销售的价格超过80元的图书,并且删掉那些重复的,那么可以使用`distinct`来实现,示例代码如下:
    ```python
    order = BookOrder.objects.filter(bookorder__price__gte=80).distinct()
    ```
    ## 需要注意的是,如果`distinct`之前使用了`order_by`,那么因为`order_by`会提取`order_by`中指定的字段,因此再使用`distinct`就会根据多个字段来进行唯一化,所以就不会把那些重复的数据删掉。示例代码如下:
    ```python
    order = BookOrder.objects.order_by('create_time').values('book_id').distinct()
    ```
    那么以上代码因为使用了`order_by`,即使使用了`distinct`,也会把重复的`book_id`提取出来。

    # update 方法
    ## 执行更新操作,在SQL底层走的也是`update`命令,比如将所有图书价格都怎加5,示例代码如下:
    ```python
    Book.objects.update(price=F("price")+5)
    ```

    # delete 方法
    ## 一次性可以把所有满足条件的数据都删除掉。
    ```python
    Author.objects.filter(id__gte=3).delete()
    ```
    ## 注意:删除的时候注意数据表之间的关系(模板中`on_delete`指定的方式)。

    # 切片操作
    ## 有时候我们查找数据,有可能只需要其中的一部分,那么这时候可以使用切片操作来帮助我们完成,`QuerySet`使用切片操作就跟列表使用切片操作是一样的,示例代码如下:
    ```python
    books = Book.objects.all()[1:2]
    ```
    切片操作并不是把所有数据从数据库中提取出来再进行切片操作,而是在数据库底层使用`limie`和`offset`来帮我们完成,所以如果只需要提取其中的一部分,建议使用切片操作。

    # 什么时候`Django`会将`QuertSet`转化为SQL去执行:
    生成一个`QuerySet`不会马上转化为SQL去执行。

    1. 迭代:在遍历`QuerySet`对象的时候,会首先执行这个SQL语句,然后再把这个结果返回进行迭代,比如以下代码:
    ```python
    for book in Book.objects.all():
    print(book)
    ```
    2. 使用步长进行切片操作:`QuerySet`可以类似于列表一样做切片操作,做切片操作本身不会执行SQL语句,但如果在做切片操作的时候提供了步长,那么就会立马执行SQL语句,需要注意的是,做切片后不能再执行`filter`方法,否则会报错。
    3. 调用`len`函数:调用`len`函数来获取`QuerySet`中总共有多少条数据也会执行SQL语句
    4. 调用`list`函数:调用`list`函数用来将一个`QuerySet`对象转化为`list`对象也会执行SQL语句
    5. 判断:如果对某个`QuerySet`进行判断,也会执行SQL语句

  • 相关阅读:
    web复制到剪切板js
    thinkphp 级联菜单实现
    一次$.getJSON不执行的记录
    php实现ppt转图片,php调用com组件问题
    模拟生成一天温度数据,精确到秒
    ffmpeg推rtmp流到crtmpserver直播
    博客新窝CSDN站
    Android开源框架Afinal第二篇——庖丁解牛,深入调查
    Android开源框架Afinal第一篇——揭开圣女的面纱
    AndroidのListView之加载说
  • 原文地址:https://www.cnblogs.com/longbigbeard/p/10158983.html
Copyright © 2011-2022 走看看