Django模型--数据库(MySQL)-查询

Django模型–数据库(MySQL)-查询

1. 模型常用字段

字段类型MySQL类型描述
IntegerFieldint整型,安全
CharFieldvarchar字符串,对于大量文本,请使用TextField
TextFieldtextmax_length属性只会影响表单部件Textarea,对数据库和模型无影响
BooleanFieldtinyint传递True/False进去。如果要可以为空,则用NullBooleanField。
DateFielddate设置DateField.auto_now每次保存对象时,自动设置该字段为当前时间。 设置DateField.auto_now_add当对象第一次被创建时自动设置当前时间。
DateTimeFielddatetime传递datetime.datetime()

2. 字段常用参数

常用参数描述
primary_keyTrue则指定该字段为模型主键,django会自动添加一个AutoField来保存主键
unique如果True,该字段在整个表格中必须是唯一的,unique意味着索引的创建。
null如果True,表示可以存储空值,null参数仅影响数据库存储
blank如果True,表单验证将允许输入空值。blank与验证相关
default设置默认值。
DateField.auto_now只有调用Model.save()方法才会调用,QuerySet.update方法将不会调用。
DateField.auto_now_add第一次添加进去,都会将当前时间设置进去。以后修改,不会修改这个值
  • 详细字段信息请访问:字段参数
  • 除非要覆盖默认的主键行为,否则任何字段不需要设置primary_key;
  • primary_key=True暗示null=Falseunique=True
  • 主键字段是只读的。如果更改现有对象上的主键值,然后保存它,则将创建一个与旧对象并排的新对象。
  • 避免null在基于字符串的字段上使用,例如 CharFieldTextField,会“无数据”有两个可能值:NULL和空字符串。Django约定是使用空字符串,而不是 NULL
  • DateField.auto_now参数只是Date和DateTime以及Time类才有的。

3. 常用查询

3.1 通过模型类的管理器构造QuerySet

3.1.1 管理器
# 管理器指的是 模型类.objects
In [27]: User.objects                                
Out[27]: <django.db.models.manager.Manager at 0x7fdca807e6d8>
3.2.2 QuerySet

QuerySet 表示数据库中对象的集合。惰性的,创建时不会立刻调用数据库,需要加载内容(比如切片,读取等)时再调用数据库。

3.2 方法

1. all
#首先返回 QuerySet 对象
In [28]: stu = User.objects.all()                    

In [29]: type(stu)                                            
Out[29]: django.db.models.query.QuerySet

#可以查看相应的 sql 语句
In [33]: print(stu.query)                                     
SELECT `book_user`.`id`, `book_user`.`name`, `book_user`.`age`, `book_user`.`gender`, `book_user`.`c_time` FROM `book_user`

#读取数据,此时调用语句返回结果
In [34]: stu                                                  
Out[34]: <QuerySet [
    <User: id<201500>name[柯南]gender()age|22|c_time:2019-03-14 02:39:15.224760+00:00>, 
    <User: id<201501>name[毛利]gender()age|22|c_time:2019-03-14 02:40:23.069295+00:00>, 
    <User: id<201502>name[元太]gender()age|22|c_time:2019-03-14 02:40:39.109599+00:00>, 
    <User: id<201504>name[高木]gender()age|22|c_time:2019-03-14 02:41:12.685040+00:00>
]>


2. first
# 获取第一条,返回对象
In [36]: User.objects.first()                                 
Out[36]: <User: id<201500>name[柯南]gender()age|22|c_time:2019-03-14 02:39:15.224760+00:00>


3. last
# 获取最后一条,返回对象
In [43]: User.objects.last()                                  
Out[43]: <User: id<201504>name[高木]gender()age|22|c_time:2019-03-14 02:41:12.685040+00:00>


4. get
#get(**kwargs) 根据传入参数查询,获取并返回一个对象,查询到多个则报错
In [45]: User.objects.get(pk=201501)                          
Out[45]: <User: id<201501>name[毛利]gender()age|22|c_time:2019-03-14 02:40:23.069295+00:00>


5. filter
#filter(**kwargs) 根据传入参数查询,获取并返回过滤后的 QuerySet ;
In [46]: User.objects.filter(gender=1)                        
Out[46]: <QuerySet [
    <User: id<201500>name[柯南]gender()age|22|c_time:2019-03-14 02:39:15.224760+00:00>, 
    <User: id<201501>name[毛利]gender()age|22|c_time:2019-03-14 02:40:23.069295+00:00>,
    <User: id<201502>name[元太]gender()age|22|c_time:2019-03-14 02:40:39.109599+00:00>, 
    <User: id<201504>name[高木]gender()age|22|c_time:2019-03-14 02:41:12.685040+00:00>
]>



6. exclude
#与filter(**kwargs)相反,根据传入参数查询,获取并返回不符合条件的的 QuerySet ;
In [50]: fil = User.objects.filter(gender=1).query            

In [51]: exc = User.objects.exclude(gender=1).query           

In [52]: print(fil)                                           
SELECT `book_user`.`id`, `book_user`.`name`, `book_user`.`age`, `book_user`.`gender`, `book_user`.`c_time` FROM `book_user` WHERE `book_user`.`gender` = 1

In [53]: print(exc)                                           
SELECT `book_user`.`id`, `book_user`.`name`, `book_user`.`age`, `book_user`.`gender`, `book_user`.`c_time` FROM `book_user` WHERE NOT (`book_user`.`gender` = 1)


7. values
# 指定字段
In [59]: fil = User.objects.filter(gender=1).values('name','gender')                                               

# 返回QuerySet
In [60]: type(fil)                                            
Out[60]: django.db.models.query.QuerySet

# 需要迭代时,返回字典列表,不再是对象列表
In [61]: fil                                                  
Out[61]: <QuerySet [
    {'name': '柯南', 'gender': 1}, 
    {'name': '毛利', 'gender': 1}, 
    {'name': '元太', 'gender': 1}, 
    {'name': '高木', 'gender': 1}
]>

  • values(*fields) 返回QuerySet, 返回字典列表
  • values 操作sqlSelectfrom关键字中间的参数部分,即提取的内容。

8. only
# 指定字段
In [65]: fil = User.objects.only('name', 'gender')                                             

# 返回QuerySet
In [66]: type(fil)                                            
Out[66]: django.db.models.query.QuerySet

# sql语句
In [68]: str(fil.query)                                       
Out[68]: 'SELECT `book_user`.`id`, `book_user`.`name`, `book_user`.`gender` FROM `book_user`'

# 需要迭代时,返回字典列表,不再是对象列表
# 此处因为重写User的__str__方法,又获取了其他字段,可以用 dir 方法证明只有属性name和gender
In [69]: fil                                                  
Out[69]: <QuerySet [
    <User: id<201500>name[柯南]gender()age|22|c_time:2019-03-14 02:39:15.224760+00:00>, 
    <User: id<201501>name[毛利]gender()age|22|c_time:2019-03-14 02:40:23.069295+00:00>, 
    <User: id<201502>name[元太]gender()age|22|c_time:2019-03-14 02:40:39.109599+00:00>, 
    <User: id<201504>name[高木]gender()age|22|c_time:2019-03-14 02:41:12.685040+00:00>
]>
    
# dir
In [70]: dir(fil[0])                                              
Out[70]: [
    ...
    'get_previous_by_c_time',
 	'id',
	'name',
 	'objects',
	'pk'
    ...
    ]


  • values(*fields) 返回QuerySet, 返回对象列表;
  • 操作sqlSelectfrom 关键字中间的参数部分,即提取的内容。但是一定包含id
  • only 还能访问其他字段,从而提取,故开发中尝试用;

9. defer
#作用和 only 相反,取出除给定字段以外的字段,一定有 id
# 指定被排除的字段
In [71]: res = User.objects.defer('c_time', 'gender', 'id')  #id 不会被排除                                            

# 返回QuerySet
In [72]: type(fil)                                            
Out[72]: django.db.models.query.QuerySet

# sql语句
In [73]: str(fil.query)                                       
Out[73]: 'SELECT `book_user`.`id`, `book_user`.`name`, `book_user`.`gender` FROM `book_user`'

# 需要迭代时,返回字典列表,不再是对象列表
In [74]: fil                                                  
Out[74]: <QuerySet [
    <User: id<201500>name[柯南]gender()age|22|c_time:2019-03-14 02:39:15.224760+00:00>, 
    <User: id<201501>name[毛利]gender()age|22|c_time:2019-03-14 02:40:23.069295+00:00>, 
    <User: id<201502>name[元太]gender()age|22|c_time:2019-03-14 02:40:39.109599+00:00>, 
    <User: id<201504>name[高木]gender()age|22|c_time:2019-03-14 02:41:12.685040+00:00>
]>

# dir
In [8]: dir(res[0])                                           
Out[8]: [
 ...
 'get_previous_by_c_time',
 'id',          # id 无法被排除,一定有
 'name',
 'objects'
 ...
 ] 

  • id 无法被排除
  • 虽然被排除在外,任然可以访问,但需要再执行获取其他字段的sql语句

10. 切片
#切片
In [16]: li_user = User.objects.all()[2:4]                    

# sql 等价语句
In [17]: print(li_user.query)                                 
SELECT `book_user`.`id`, `book_user`.`name`, `book_user`.`age`, `book_user`.`gender`, `book_user`.`c_time` FROM `book_user`  LIMIT 2 OFFSET 2
#注意,切片[m:m]合理,但转化为sql语句时,‘limit 0’会抛出异常,故避免

#显示数据
In [18]: li_user                                              
Out[18]: <QuerySet [
    <User: id<201502>name[元太]gender()age|22|c_time:2019-03-14 02:40:39.109599+00:00>, 
    <User: id<201504>name[高木]gender()age|22|c_time:2019-03-14 02:41:12.685040+00:00>
]>


  • 不支持负索引
  • 可以用步长,但不推荐,效率低下
  • 切片返回 对象列表 ,故不能再排序或过滤(等QuerySet方法)
11. 延伸

更多方法详见:官方文档


4. 查询条件

4.1. Q 对象

多条件的 or and 等查询需要 Q 对象:django.db.models.Q

1. AND(&

以下是等效的:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))

#sql等价语句:SELECT ... WHERE x=1 AND y=2

2. OR(|

以下是等效的:

Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))

#sql等价语句:SELECT ... WHERE x=1 OR y=2


4.2. 字段查找

字段查找是指定SQL WHERE子句的内容的方式。它们被指定为QuerySet 方法的关键字参数filter()exclude()以及get()

语法格式:Entry.objects.func(字段名__关键字=参数)

#举个栗子: 取出 dob 小于 '2006-01-01' 的
Entry.objects.filter(dob__lte='2006-01-01')
#等价sql:SELECT * FROM blog_entry WHERE dob <= '2006-01-01';


1. exact

“精确”匹配。例如:

Entry.objects.get(headline__exact="Cat bites dog")
#生成SQL:SELECT ... WHERE headline = 'Cat bites dog';


2. iexact

不区分大小写的匹配项。所以,查询:

Blog.objects.get(name__iexact="beatles blog")
'''
会匹配Blog标题,甚至是。
"Beatles Blog"
"beatles blog"
"BeAtlES blOG"
...
'''


3. contains

区分大小写的遏制测试。例如

Entry.objects.get(headline__contains='Lennon')

#大致翻译为这个SQL:SELECT ... WHERE headline LIKE '%Lennon%';

还有一个不区分大小写的版本icontains


4. in

在给定的可迭代中; 通常是列表,元组或查询集。它不是常见的用例,但接受字符串(可迭代)。

Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')

SQL等价物:

SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');


5. gt

例:

Entry.objects.filter(id__gt=4)

SQL等价物:

SELECT ... WHERE id > 4;

还有:gte,lt,lte


6. startswith

区分大小写的开头。

例:

Entry.objects.filter(headline__startswith='Lennon')

SQL等价物:

SELECT ... WHERE headline LIKE 'Lennon%';

此外还有istartswith ,在此基础上不区分大小写


7. endswith

区分大小写的结尾。

例:

Entry.objects.filter(headline__endswith='Lennon')

SQL等价物:

SELECT ... WHERE headline LIKE '%Lennon';

同样,存在iendswith


8. range

范围测试(包括在内)。

例:

import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL等价物:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

您可以在SQL中使用的range任何地方使用BETWEEN- 包括日期,数字甚至字符。


9.date

对于datetime字段,将值转换为日期。允许链接其他字段查找。采用日期值。

例:

Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

USE_TZTrue,字段被滤波之前转换为当前时区。

同样存在 yearmonthdayweekweek_daytimehourminutesecond


10 isnull

采用任一TrueFalse,其对应于SQL查询 和分别。IS NULL``IS NOT NULL

例:

Entry.objects.filter(pub_date__isnull=True)

SQL等价物:

SELECT ... WHERE pub_date IS NULL;


11. order_by

默认情况下,a返回的结果按模型中选项QuerySet给出的排序元组排序。您可以使用该方法在每个基础上覆盖它。``

例:

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

上面的结果将按pub_date降序排序,然后按 headline升序排序。前面的负号"-pub_date"表示 降序。升序是隐含的。要随机订购,请使用"?",如下所示:

Entry.objects.order_by('?')

注意:order_by('?')查询可能很昂贵且速度很慢,具体取决于您使用的数据库后端。

要按不同模型中的字段进行排序,请使用与查询模型关系时相同的语法。也就是说,字段的名称,后跟双下划线(__),后跟新模型中字段的名称,依此类推,因为您想要加入多个模型。例如:

Entry.objects.order_by('blog__name', 'headline')


5. 聚合

通过管理器QuerySetaggregate方法实现,详见: 官方文档

In [22]: from django.db.models import Avg                     

In [23]: User.objects.aggregate(Avg('age'))                   
Out[23]: {'age__avg': 22.0}


上例中取出age字段平均值

5.0 aggregate 和 annotate

上例子

# aggregate 
In [22]: agg = User.objects.aggregate(Max('age'))  
    
In [23]: type(agg)                                                               
Out[23]: dict

In [25]: agg                                                                     
Out[25]: {'age__max': 22}
#aggregate 是在整张表中取‘age’字段最大值

# annotate
In [26]: ann = User.objects.annotate(Max('age'))                                 

In [27]: type(ann)                                                               
Out[27]: django.db.models.query.QuerySet

In [28]: type(ann[0])                                                            
Out[28]: book.models.User
# 返回对象集合

In [30]: for i in ann: 
    ...:     print(i.age__max) 
    ...:                                                                         
22
22
22
22
#annotate 为每一条记录取'age'字段最大值



5.1 Avg

In [46]: res = User.objects.aggregate(Avg('age'))                                

In [47]: res                                                                     
Out[47]: {'age__avg': 22.0}


  • class Avg(expression, output_field=FloatField(), **extra)[source]。这只是参数,构造方法见源码Avg类父类构造函数
  • 返回给定表达式的平均值,它必须是数值,除非指定不同的output_field。
  • 默认的别名:字段__avg;返回类型:float(或指定任何output_field的类型)

5.2 Count

# class Count(expression, distinct=False, **extra)[source]
In [50]: res = User.objects.filter(age=22).aggregate(Count('age'))               

In [51]: res                                                                     
Out[51]: {'age__count': 4}

#distinct=True
In [52]: res = User.objects.filter(age=22).aggregate(Count('age', distinct=True))
    ...:                                                                         

In [53]: res                                                                     
Out[53]: {'age__count': 1}


  • 返回与expression相关的对象的个数;
  • 默认的别名:字段__count;返回类型:int
  • 有一个可选的参数:distinct。如果distinct=True,Count 将只计算唯一的实例。默认值为False。

5.3 Max

#class Max(expression, output_field=None, **extra)[source]

In [5]: res = User.objects.aggregate(Max('pk'))                                  

In [6]: res                                                                      
Out[6]: {'pk__max': 201504}


  • 返回expression的最大值。
  • 默认的别名:__max;
  • 返回类型:与输入字段的类型相同,如果提供则为output_field类型

5.4 Min

#class Min(expression, output_field=None, **extra)[source]
In [7]: res = User.objects.aggregate(Min('pk'))                                  

In [8]: res                                                                      
Out[8]: {'pk__min': 201500}


  • 返回expression的最小值。
  • 默认的别名:__min;
  • 返回类型:与输入字段的类型相同,如果提供则为output_field类型

5.5 StdDev

# class StdDev(expression, sample=False, **extra)[source]
In [9]: User.objects.aggregate(StdDev('pk'))                                     
Out[9]: {'pk__stddev': 1.479019945774904}


  • 返回expression的标准差。
  • 默认的别名:__stddev;
  • 返回类型:float;
  • 有一个可选的参数:sample。默认情况下,返回群体的标准差。如果sample=True,返回样本的标准差。SQLite 没有直接提供StdDev。

5.6 Variance

#class Variance(expression, sample=False, **extra)[source]
In [10]: User.objects.aggregate(Variance('pk'))                                  
Out[10]: {'pk__variance': 2.1875}


  • 返回expression的方差。
  • 默认的别名:__variance
  • 返回类型:float
  • 有一个可选的参数:sample。SQLite 没有直接提供Variance。

5.7 Sum

# class Sum(expression, output_field=None, **extra)[source]
In [12]: User.objects.aggregate(Sum('age'))                                      
Out[12]: {'age__sum': 88}


  • 计算expression的所有值的和。
  • 默认的别名:__sum;
  • 返回类型:与输入字段的类型相同,如果提供则为output_field类型

6. 分组

6.1 认知

分组是基于聚合(annotate)的对数据进一步归类,分组一定要有聚合

6.2 使用

In [21]: User.objects.values('gender').annotate(人数=Count('pk'))                
Out[21]: <QuerySet [{'人数': 4, 'gender': 1}, {'人数': 2, 'gender': 0}]>
    
#sql 
In [24]: res = User.objects.values('gender').annotate(人数=Count('pk'))          

In [25]: str(res.query)                                                          
Out[25]: 'SELECT `book_user`.`gender`, COUNT(`book_user`.`id`) AS `人数` FROM `book_user` GROUP BY `book_user`.`gender` ORDER BY NULL'



  • 这是最简单的分组,基于提取关键字段达到分组效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值