字段类型 | MySQL类型 | 描述 |
---|---|---|
IntegerField | int | 整型,安全 |
CharField | varchar | 字符串,对于大量文本,请使用TextField 。 |
TextField | text | max_length属性只会影响表单部件Textarea ,对数据库和模型无影响 |
BooleanField | tinyint | 传递True/False进去。如果要可以为空,则用NullBooleanField。 |
DateField | date | 设置DateField.auto_now每次保存对象时,自动设置该字段为当前时间。 设置DateField.auto_now_add当对象第一次被创建时自动设置当前时间。 |
DateTimeField | datetime | 传递datetime.datetime() |
常用参数 | 描述 |
---|---|
primary_key | 为True则指定该字段为模型主键,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=True
暗示null=False
和 unique=True
。null
在基于字符串的字段上使用,例如 CharField
和TextField
,会“无数据”有两个可能值:NULL
和空字符串。Django约定是使用空字符串,而不是 NULL
。DateField.auto_now
参数只是Date和DateTime以及Time类才有的。# 管理器指的是 模型类.objects
In [27]: User.objects
Out[27]: <django.db.models.manager.Manager at 0x7fdca807e6d8>
QuerySet 表示数据库中对象的集合。惰性的,创建时不会立刻调用数据库,需要加载内容(比如切片,读取等)时再调用数据库。
#首先返回 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>
]>
# 获取第一条,返回对象
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>
# 获取最后一条,返回对象
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>
#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>
#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>
]>
#与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)
# 指定字段
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
操作sql
中 Select
和from
关键字中间的参数部分,即提取的内容。# 指定字段
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'
...
]
sql
中 Select
和 from
关键字中间的参数部分,即提取的内容。但是一定包含id
;#作用和 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'
...
]
sql
语句#切片
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>
]>
更多方法详见:官方文档
多条件的 or and 等查询需要 Q 对象:django.db.models.Q
&
)以下是等效的:
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
|
)以下是等效的:
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
字段查找是指定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';
“精确”匹配。例如:
Entry.objects.get(headline__exact="Cat bites dog")
#生成SQL:SELECT ... WHERE headline = 'Cat bites dog';
不区分大小写的匹配项。所以,查询:
Blog.objects.get(name__iexact="beatles blog")
'''
会匹配Blog标题,甚至是。
"Beatles Blog"
"beatles blog"
"BeAtlES blOG"
...
'''
区分大小写的遏制测试。例如
Entry.objects.get(headline__contains='Lennon')
#大致翻译为这个SQL:SELECT ... WHERE headline LIKE '%Lennon%';
还有一个不区分大小写的版本icontains
。
在给定的可迭代中; 通常是列表,元组或查询集。它不是常见的用例,但接受字符串(可迭代)。
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');
例:
Entry.objects.filter(id__gt=4)
SQL等价物:
SELECT ... WHERE id > 4;
还有:gte,lt,lte
区分大小写的开头。
例:
Entry.objects.filter(headline__startswith='Lennon')
SQL等价物:
SELECT ... WHERE headline LIKE 'Lennon%';
此外还有istartswith
,在此基础上不区分大小写
区分大小写的结尾。
例:
Entry.objects.filter(headline__endswith='Lennon')
SQL等价物:
SELECT ... WHERE headline LIKE '%Lennon';
同样,存在iendswith
范围测试(包括在内)。
例:
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
- 包括日期,数字甚至字符。
对于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_TZ
是True
,字段被滤波之前转换为当前时区。
同样存在 year
,month
,day
,week
,week_day
,time
,hour
,minute
,second
采用任一True
或False
,其对应于SQL查询 和分别。IS NULL``IS NOT NULL
例:
Entry.objects.filter(pub_date__isnull=True)
SQL等价物:
SELECT ... WHERE pub_date IS NULL;
默认情况下,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')
通过管理器QuerySet
的 aggregate
方法实现,详见: 官方文档
In [22]: from django.db.models import Avg
In [23]: User.objects.aggregate(Avg('age'))
Out[23]: {'age__avg': 22.0}
上例中取出age
字段平均值
上例子
# 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'字段最大值
In [46]: res = User.objects.aggregate(Avg('age'))
In [47]: res
Out[47]: {'age__avg': 22.0}
# 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}
#class Max(expression, output_field=None, **extra)[source]
In [5]: res = User.objects.aggregate(Max('pk'))
In [6]: res
Out[6]: {'pk__max': 201504}
output_field
类型#class Min(expression, output_field=None, **extra)[source]
In [7]: res = User.objects.aggregate(Min('pk'))
In [8]: res
Out[8]: {'pk__min': 201500}
output_field
类型# class StdDev(expression, sample=False, **extra)[source]
In [9]: User.objects.aggregate(StdDev('pk'))
Out[9]: {'pk__stddev': 1.479019945774904}
#class Variance(expression, sample=False, **extra)[source]
In [10]: User.objects.aggregate(Variance('pk'))
Out[10]: {'pk__variance': 2.1875}
# class Sum(expression, output_field=None, **extra)[source]
In [12]: User.objects.aggregate(Sum('age'))
Out[12]: {'age__sum': 88}
分组是基于聚合(annotate)的对数据进一步归类,分组一定要有聚合
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'