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%';
  • 相关阅读:
    Powershell数据处理
    Powershell About Active Directory Group Membership of a domain user
    Powershell About Active Directory Server
    Oracle Schema Objects——Tables——TableStorage
    Oracle Schema Objects——Tables——TableType
    English Grammar
    Oracle Database Documentation
    Oracle Schema Objects——Tables——Oracle Data Types
    Oracle Schema Objects——Tables——Overview of Tables
    What is Grammar?
  • 原文地址:https://www.cnblogs.com/timlinux/p/9230005.html
Copyright © 2011-2022 走看看