zoukankan      html  css  js  c++  java
  • [TimLinux] django model关于QuerySet

    1. 获取执行过的sql命令

    from django.db import connections
    connections['default'].queries

    2. 获取QuerySet将执行的sql语句

    qs = Entries.object.all()
    print(qs.query)

    3. 单一模型:增删改查

    模型示例:

    from django.db import models
    class Student(models.Model):
        name = models.CharField(max_length=30)
        sex = models.CharField(max_length=30)

    3.1. 增

    #构造函数方式增加数据
    s1 = Student(name='Tim', sex='Male')
    s1.save()  #只有这步才执行了insert操作。
    
    #管理对象方式增加数据
    s1 = Student.objects.create()  #已经执行了一次insert操作了。
    s1.name = "Tim"
    s1.sex = "Male"
    s1.save()  #这步是update操作

    3.2. 删

    # query set方式删除:这个方式,只执行了一次sql
    qs = Student.objects.filter(pk=1)  # 这个返回的是QuerySet
    qs.delete()
    
    # 对象方式删除:这个方式,执行了两次sql
    s1 = Student.objects.get(pk=1)  # 这个返回的是RA对象
    s1.delete()

     3.3. 改

    #直接在qs上操作数据的更新,对应的是sql的 update语句
    from django.db import models
    from django.db.models import functions
    
    qs
    = Student.objects.filter(id__in=[1,2,3]) qs.update(name=functions.Concat('name', models.Value("appendStr"), output_field=models.CharField)) #操作对象的方式,对应的是,select,然后针对每一行,update。 qs = Student.objects.filter(id__in=[1,2,3]) for t in qs: t.name = t.name + "appendStr" t.save()

     3.4. 查

    查询接口分为两类,返回新的QuerySet对象的接口,和不返回QuerySet对象的接口,清单如下:

    #返回新的QuerySet对象的接口
    filter             exclude         annotate        order_by      reverse
    distinct           values          values_list     dates         none
    all                union           intersection    difference    select_related
    prefetch_related   extra           defer           only          using
    select_for_update  raw
    
    #不返回QuerySet对象的接口
    get     create     get_or_create      update_or_create   bulk_create
    count   in_bulk    iterator           latest             earliest
    first   last       aggregate          exists             update
    delete as_manager

     QuerySet特点:

    • 链式过滤:
    • 每一次过滤得到的QuerySet都是唯一的
    • QuerySet是惰性的

    QuerySet真实发生SQL操作的时机:

    • 迭代操作:
    • 切片操作:LIMIT SQL语句
    • Pickling/Caching:
    • repr()函数:
    • len()函数:建议是用Count()
    • list()函数:
    • bool()函数:建议使用exists()

    3.4.1. 返回QuerySet对象函数

    • filter(**kwargs):只接收关键字参数,格式为Field lookup语法格式,多个参数间是 AND 关系,使用models.Q可以修改参数间的关系。
    • exclude(**kwargs):与 filter 一样的参数格式,选择的方式为取反(NOT),是在整个参数之外增加NOT(参数逻辑),参数内还是 AND 关系
    • annotate(*args, **kwargs):aggregate()是聚合操作,annotate则是在聚合的基础上进行了GROUP BY操作。针对的对象是:由”查询表达式”获取的QuerySet对象中的每一个对象。
      • 查询表达式(Query Expressions):一个简单的值、模型(或关联模型)中的一个字段的引用、或者一个聚合表达式(Aggregate:avg,sum,count等)。查询表达式描述了一个值、或者一种运算:使用在更新(update)、创建(create)、过滤(filter)、排序(order by)、注解(annotate)、聚合(aggregate)中。许多内建表达式帮助我们写查询。表达式可以组合、或者在某些场景下嵌套来组成更复杂的运算。
        • 支持数学运算:支持加、减、乘、除、取模数学运算,以及指数操作(使用Python常量、变量、或者其他表达式来实现)
          • 加法:Company.objects.filter( num_employees__gt=F('num_chairs') + F('num_chairs) )  字段值翻倍
          • 乘法:Company.objects.filter( num_employees__gt=F('num_chairs') * 2 )  字段值翻倍
          • 减法:Company.objects.annotate( chairs_needed=F('num_employees') - F('num_chairs') ) 
        • 内建表达式:被定义在 django.db.models.expressions 和 django.db.models.aggregates 中,通常import django.db.models即可使用
          • F()表达式:数据库内,对字段进行运算操作,没必要将值先存入Python,然后再计算。F()表达式会在每次调用save()操作都执行一次
          • Func()表达式:所以调用数据函数表达式的基础表达式。
          • Aggregate()表达式:封装GROUP BY, 是其他聚合类Sum, Count等的父类。
          • Value()表达式:表达式中需要传递值(整数、bool、字符串)时,直接使用Value对值进行转换后使用。
          • ExpressionWrapper()表达式:简单包装另外一个表达式,并提供访问属性(output_field),F()表达式做算术运算时常用到。
          • Subquery()表达式:添加子查询到一个QuerySet对象中。
          • RawSQL表达式:无法写复杂的WHERE从句时,直接使用RawSQL表达式实现。
      • QuerySet对象中的每一个对象:
        • annotate中的每一个参数,都将被添加到QuerySet返回的每一个对象中。
        • 关键字参数,将成为返回对象的属性名。
        • 匿名参数,返回的对象属性名,将由"字段名__聚合函数名"组成,全小写格式。
        • 只有聚合函数引用单一字段时,可以使用匿名参数,其他都必须使用关键字参数。
    # 1. F()表达式
    #--------------------------------
    #
    不好的操作方式 reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed += 1 # select stories_filed from reporter where name='Tintin'; 然后把字段存入Python内存,并处理 reporter.save() # update reporter set stories_filed=5 where id=1; 写入的时候是具体的值。 # 好的操作方式:使用F()表达式 from django.db.models import F reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed = F('stories_filed') + 1 reporter.save() # update reporter set stories_filed=stories_filed+1 where name='Tintin';

    # 更好的方式:使用F()表达式
    reporter = Repoters.objects.get(name='Tintin')
    reporter.update( stories_filed=F('stories_filed') + 1 )

    # 甚至一次操作所有对象
    Repoters.objects.all().update( stories_filed=F('stories_filed') + 1 )

    # F()表达式的注意事项:每次调用save都会执行F表达式,以下的示例,stories_filed将被增加2.
    reporter = Reporters.objects.get(name='Tintin')
    reporter.stories_filed = F('stories_filed') + 1
    reporter.save()

    reporter.name = 'Tintin Jr.'
    reporter.save()

    # F()表达式还可以用在:filter、annotate中。

    # 2. Func()表达式
    #--------------------------------
    # 所有函数都可以通过Func表达式来实现
    from django.db.models import Func, F
    queryset.annotate( field_lower=Func(F('field'), function='LOWER') ) # sql: SELECT ..., LOWER(field) AS field_lower FROM ...

    # 通过继承Func,实现自定义函数接口
    class Lower(Func):
    function = 'LOWER'
    queryset.annotate( field_lower=Lower('field') )

    # 3. Aggregate()表达式
    #--------------------------------
    # 是Func表达式的一个特定场景,使用GROUP BY从句,所有聚合函数都是继承自Aggregate表达式:Sum,Count。
    # Aggregate是表达式、包装表达式,为此可以实现一些复杂的运算
    Company.objects.annotate( managers_required=(Count('num_employees') / 4) + Count('num_managers') )

    # 4. Value() 表达式
    #--------------------------------
    F('field') + 1 === F('field') + Value(1)
    F('field') + '-append' # 这个会报错
    F('field') + Value('-append') # 这样也会报错
    Concat( 'field', Value('-append'), output_field=CharField ) # 这样就不会报错了

    # 5. ExpressionWrapper()表达式
    #--------------------------------
    Ticket.objects.annotate( expires=ExpressionWrapper( F('active_at') + F('duration'), output_field=DateTimeField() ) )

    # 6. Subquery() 表达式
    #--------------------------------
    # 给一个QuerySet添加一个明确的子查询
    # OuterRef('pk') 引用外部QuerySet数据库中的pk字段, 与同一个model中的F()表达式类似
    # 子查询需要使用values()指定返回单一的列属性值,以下例子只返回了 emails.

    newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
    Post.objects.annotate(newest_commenter_email=Subquery(newest.values('emails')[:1]))
    # PostgreSQL语句:
    # SELECT post.id, (子查询在这里) AS newest_commenter_email FROM post;
    # 子查询: SELECT comment.emails FROM comment WHERE comment.post_id=post.id ORDER BY created_at DESC LIMIT 1;
    # Exists() 是Subquery()类的子类,使用的是SQL的 EXISTS语句
    from django.db.models import Exists, OuterRef
    from datetime import timedelta
    from django.utils import timezone
    one_day_ago = timezone.now() - timedelta(days=1)
    recent_comments = Comment.objects.filter( post=OuterRef('pk'), created_at__gte=one_day_ago )
    Post.objects.annotate( recent_comment=Exists(recent_comments) )
    # PostgreSQL语句:
    # SELECT post.id, post.published_at, EXISTS(子查询) AS recent_comment FROM post;
    # 子查询:SELECT comment.id, comment.post_id, comment.email, comment.craeted_at FROM comment
    # WHERE (comment.craeted_at >= YYYY-MM-DD HH:MM:SS AND comment.post_id=post.id);

    # 过滤子查询,需要先在annotate中运行子查询,然后filter过滤字段值
    # 在子查询表达式中使用聚合

    # 7. Raw SQL表达式
    #--------------------------------
    from django.db.models.expressions import RawSQL
    queryset.annotate( val=RawSQL('select col from sometable where othercol=%s', (someparam,) )
    • order_by:
    • reverse:
    • distinct:
    • values:
    • values_list:
    • dates:
    • datetimes:
    • none:
    • all:
    • union:
    • intersection:
    • difference:
    • select_related:
    • prefetch_related:
    • extra:
    • defer:
    • only:
    • using:
    • select_for_update:
    • raw:

    3.4.2. 不返回QuerySet对象函数

    • get:
    • create:
    • get_or_create:
    • update_or_create:
    • bulk_create:
    • count:
    • in_bulk:
    • iterator:
    • latest:
    • earliest:
    • first:
    • last:
    • aggregate:
    • exists:
    • update:
    • delete:
    • as_manager:

    3.5. Field查询

    Field lookup:用来指定SQL查询中WHERE从句部分内容的,作为filter、exclude、get函数的关键字参数,格式:字段名__查询类型,字段名来自model的定义部分,然后带双下划线,接下来为Django语句支持的查询类型关键字:

    # i开头表示,忽略大小写
    # exact, 对应SQL语句: =
    # iexact,对应SQL语句: LIKE (LIKE是不区分大小写的)
    # contains,对应SQL语句: LIKE BINARY (LIKE BINARY是区分大小写的)
    # icontain,对应SQL语句: LIKE

    exact iexact contains icontains in gt gte lt lte startswith istartswith endswith iendswith range date year month day week week_day time hour minute second isnull search regex iregex

    #查询示例: name是字段名,exact是查询关键字,中间使用双下划线连接
    Student.objects.filter(name__exact="tim")
    # SQL:
    SELECT `student`.`id` `student`.`name` FROM `student` WHERE `student`.`name` = 'tim';

    Student.objects.filter(name__iexact="tim")
    # SQL: SELECT `student`.`id` `student`.`name` FROM `student` WHERE `student`.`name` LIKE 'tim';

    Student.objects.filter(name__contain="tim")
    # SQL: SELECT `student`.`id` `student`.`name` FROM `student` WHERE `student`.`name` LIKE BINARY '%tim%';

    Student.objects.filter(name__icontain="tim")
    # SQL: SELECT `student`.`id` `student`.`name` FROM `student` WHERE `student`.`name` LIKE '%tim%';
  • 相关阅读:
    .Net组件程序设计
    Product Trader(操盘手)
    IOC 容器在 ASP.NET MVC 中的应用
    Visual Studio 2013发布Cloud Service至Azure China
    SignalR 2.0 入门与提高
    C# RFID windows 服务 串口方式
    Properties文件及与之相关的System.getProperties操作(转)
    使用ssh远程执行命令批量导出数据库到本地(转)
    关于Linux路由表的route命令(转)
    Can't call commit when autocommit=true(转)
  • 原文地址:https://www.cnblogs.com/timlinux/p/9230005.html
Copyright © 2011-2022 走看看