【一】引入
一些说明:
- 表myapp_person的名称是自动生成的,如果你要自定义表名,需要在model的Meta类中指定 db_table 参数,强烈建议使用小写表名,特别是使用MySQL作为后端数据库时。
- id字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定 primary_key=True 即可。
- 如果Django发现你已经明确地设置了Field.primary_key,它将不会添加自动ID列。
- 本示例中的CREATE TABLE SQL使用PostgreSQL语法进行格式化,但值得注意的是,Django会根据配置文件中指定的数据库后端类型来生成相应的SQL语句。
- Django支持MySQL5.5及更高版本。
【二】常用字段
【1】AutoField
- int自增列
- 必须填入参数 primary_key=True。
- 当model中如果没有自增列,则自动会创建一个列名为id的列。
【2】IntegerField
- 一个整数类型
- 范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
【3】CharField
- 字符类型,必须提供max_length参数, max_length表示字符长度。
- 这里需要知道的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,但是Django允许我们自定义新的字段,下面我来自定义对应于数据库的char类型
自定义字段在实际项目应用中可能会经常用到,这里需要对他留个印象!
from django.db import models # Create your models here. #Django中没有对应的char类型字段,但是我们可以自己创建 class FixCharField(models.Field): ''' 自定义的char类型的字段类 ''' def __init__(self,max_length,*args,**kwargs): self.max_length=max_length super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): ''' 限定生成的数据库表字段类型char,长度为max_length指定的值 :param connection: :return: ''' return 'char(%s)'%self.max_length #应用上面自定义的char类型 class Class(models.Model): id=models.AutoField(primary_key=True) title=models.CharField(max_length=32) class_name=FixCharField(max_length=16) gender_choice=((1,'男'),(2,'女'),(3,'保密')) gender=models.SmallIntegerField(choices=gender_choice,default=3)
【4】DateField
- 日期字段
- 日期格式 YYYY-MM-DD
- 相当于Python中的datetime.date()实例。
【5】DateTimeField
- 日期时间字段
- 格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
- 相当于Python中的datetime.datetime()实例。
【三】字段合集
【1】AutoField(Field)
- int自增列
- 必须填入参数 primary_key=True
【2】BigAutoField(AutoField)
- bigint自增列
- 必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32)
【3】SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
【4】BooleanField(Field)
- 布尔值类型
【5】NullBooleanField(Field):
- 可以为空的布尔值
【6】CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
【7】TextField(Field)
- 文本类型
【8】EmailField(CharField):
- 字符串类型
- Django Admin以及ModelForm中提供验证机制
【9】IPAddressField(Field)
- 字符串类型
- Django Admin以及ModelForm中提供验证 IPV4 机制
【10】GenericIPAddressField(Field)
- 字符串类型
- Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
- protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
- unpack_ipv4
- 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
【11】URLField(CharField)
- 字符串类型
- Django Admin以及ModelForm中提供验证 URL
【12】SlugField(CharField)
- 字符串类型
- Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
【13】CommaSeparatedIntegerField(CharField)
- 字符串类型
- 格式必须为逗号分割的数字
【14】UUIDField(Field)
- 字符串类型
- Django Admin以及ModelForm中提供对UUID格式的验证
【15】FilePathField(Field)
- 字符串
- Django Admin以及ModelForm中提供读取文件夹下文件的功能
参数: path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹
【16】FileField(Field)
- 字符串
- 路径保存在数据库,文件上传到指定目录
参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
【17】ImageField(FileField)
- 字符串
- 路径保存在数据库,文件上传到指定目录
参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串)
【18】DateTimeField(DateField)
- 日期+时间格式
- YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
【19】DateField(DateTimeCheckMixin, Field)
- 日期格式
- YYYY-MM-DD
【20】TimeField(DateTimeCheckMixin, Field)
- 时间格式
- HH:MM[:ss[.uuuuuu]]
【21】DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
【22】FloatField(Field)
- 浮点型
【23】DecimalField(Field)
- 10进制小数
参数: max_digits,小数总长度 decimal_places,小数位长度
【24】BinaryField(Field)
- 二进制类型
【四】字段参数
【1】null
- 用于表示某个字段可以为空。
【2】unique
- 如果设置为unique=True 则该字段在此表中必须是唯一的 。
【3】db_index
- 如果db_index=True 则代表着为此字段设置索引。
【4】default
- 为该字段设置默认值。
【五】DateField和DateTimeField
【1】auto_now_add
- 配置auto_now_add=True
- 创建数据记录的时候会把当前时间添加到数据库。
【2】auto_now
- 配置上auto_now=True
- 每次更新数据记录的时候会更新该字段。
【六】关系字段 ForeignKey
- 外键类型在ORM中用来表示外键关联关系
- 一般把ForeignKey字段设置在 '一对多'中'多'的一方。
- ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
【七】ForeignKey 字段参数
【1】to
- 设置要关联的表
【2】to_field
- 设置要关联的表的字段
【3】on_delete
- 当删除关联表中的数据时,当前表与其关联的行的行为。
【4】models.CASCADE
- 删除关联数据,与之关联也删除
【5】其他on_delete参数
1、models.CASCADE
- 级联操作
- 当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
2、models.SET_NULL
- 当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null
- 此时注意定义外键时,这个字段必须可以允许为空
3、models.PROTECT
- 当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
4、models.SET_DEFAULT
- 当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值
- 此时注意定义外键时,这个外键字段应该有一个默认值
5、models.SET()
- 当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值
- 与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
6、models.DO_NOTHING
- 什么都不做
- 一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
【6】代码配置
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id",
on_delete=models.SET(func)
)
【八】ForeignKey操作
【1】正向查找(两种方式)
1.对象查找(跨表)
- 语法:
对象.关联字段.字段
要点:先拿到对象,再通过对象去查对应的外键字段,分两步
- 示例:
book_obj = models.Book.objects.first() # 第一本书对象(第一步)
print(book_obj.publisher) # 得到这本书关联的出版社对象
print(book_obj.publisher.name) # 得到出版社对象的名称
2.字段查找(跨表)
- 语法:
关联字段__字段
要点:利用Django给我们提供的神奇的双下划线查找方式
- 示例:
models.Book.objects.all().values("publisher__name")
#拿到所有数据对应的出版社的名字,神奇的下划线帮我们夸表查询
【2】反向操作(两种方式)
1.对象查找
- 语法:
obj.表名_set
要点:先拿到外键关联多对一,一中的某个对象,由于外键字段设置在多的一方,所以这里还是借用Django提供的双下划线来查找
- 示例:
publisher_obj = models.Publisher.objects.first() # 找到第一个出版社对象
books = publisher_obj.book_set.all() # 找到第一个出版社出版的所有书
titles = books.values_list("title") # 找到第一个出版社出版的所有书的书名
结论:如果想通过一的那一方去查找多的一方,由于外键字段不在一这一方,所以用__set来查找即可
2.字段查找
- 语法:
表名__字段
要点:直接利用双下滑线完成跨表操作
titles = models.Publisher.objects.values("book__title")
【九】OneToOneField
- 一对一字段。
- 通常一对一字段用来扩展已有字段。
- (通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)
【十】OneToOneField 字段参数
【1】to
- 设置要关联的表。
【2】to_field
- 设置要关联的字段。
【3】on_delete
- 当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)
【十一】ManyToManyField
【1】class RelatedManager
- "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。
它存在于下面两种情况:
- 外键关系的反向查询
- 多对多关联关系
- 简单来说就是在多对多表关系并且这一张多对多的关系表是有Django自动帮你建的情况下,下面的方法才可使用。
【2】方法
(1)create()
- 创建一个关联对象,并自动写入数据库,且在第三张双方的关联表中自动新建上双方对应关系。
models.Author.objects.first().book_set.create(title="偷塔秘籍")
上面这一句干了哪些事儿:
1.由作者表中的一个对象跨到书籍比表
2.新增名为偷塔秘籍的书籍并保存
3.到作者与书籍的第三张表中新增两者之间的多对多关系并保存
(2)add()
-
把指定的model对象添加到第三张关联表中。
-
添加对象
>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)
- 添加id
>>> models.Book.objects.first().authors.add(*[1, 2])
(3)set()
- 更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])
(4)remove()
- 从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系)
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)
(5)clear()
- 从关联对象集中移除一切对象。(移除所有与对象相关的关系信息)
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.clear()
注意:
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
(6)举个例子:
- ForeignKey字段没设置null=True时,
class Book(models.Model):
title = models.CharField(max_length=32)
publisher = models.ForeignKey(to=Publisher)
- 没有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'clear'
- 当ForeignKey字段设置null=True时,
class Book(models.Model):
name = models.CharField(max_length=32)
publisher = models.ForeignKey(to=Class, null=True)
- 此时就有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()
再次强调:
对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。
换句话说,在关联的任何一端,都不需要再调用save()方法。
【十二】在Python脚本中调用Django环境
- 一般操作
- 在进行一般操作时先配置一下参数,使得我们可以直接在Django页面中运行我们的测试脚本
这样就可以直接运行你的test.py文件来运行测试
【十三】必知必会13条
- 操作下面的操作之前,我们实现创建好了数据表,这里主要演示下面的操作,不再细讲创建准备过程
**【1】all(): **
- 查询所有结果
**【2】filter(**kwargs): **
- 它包含了与所给筛选条件相匹配的对象
**【3】get(**kwargs): **
- 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
**【4】exclude(**kwargs): **
- 它包含了与所给筛选条件不匹配的对象
**【5】values(*field): **
- 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
**【6】values_list(*field): **
- 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
**【7】order_by(*field): **
对查询结果排序
**【8】reverse(): **
- 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
**【9】distinct(): **
- 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
**【10】count(): **
- 返回数据库中匹配查询(QuerySet)的对象数量。
**【11】first(): **
- 返回第一条记录
**【12】last(): **
- 返回最后一条记录
**【13】exists(): **
- 如果QuerySet包含数据,就返回True,否则返回False
【十四】13个必会操作总结
【1】返回QuerySet对象的方法
(1)all():
- 该方法返回一个包含所有记录的QuerySet对象。
- 示例:
objects.all()
(2)filter(**kwargs):
- 该方法返回一个满足筛选条件的QuerySet对象。
- 可以使用关键字参数来指定筛选条件,如
field_name=value
。 - 示例:
objects.filter(name='John')
(3)exclude(**kwargs):
- 该方法返回一个不满足筛选条件的QuerySet对象。
- 可以使用关键字参数来指定筛选条件,如
field_name=value
。 - 示例:
objects.exclude(age__lt=18)
(4)order_by(*fields):
- 该方法用于对QuerySet对象进行排序,并返回排序后的QuerySet对象。
- 可以传入一个或多个字段作为参数,使用负号(-)表示降序排序。
- 示例:
objects.order_by('name', '-age')
(5)reverse():
- 该方法用于将QuerySet对象中的记录顺序反转,并返回反转后的QuerySet对象。
- 示例:
objects.reverse()
(6)distinct(*fields):
- 该方法用于查询不重复的记录,返回一个去重后的QuerySet对象。
- 可以传入一个或多个字段作为参数,只返回在指定字段上不重复的记录。
- 示例:
objects.distinct('category')
【2】特殊的QuerySet
(1)values()
-
返回一个可迭代的字典序列
-
values()
方法返回一个可迭代的字典序列,每个字典表示一个查询结果对象,并且字典的键是字段名,值是该字段的值。 -
你可以使用
values()
方法指定要获取的字段,也可以使用其他查询方法进行过滤、排序等操作。 -
示例代码:
python# 获取学生表中所有学生的姓名和年龄
student_data = Student.objects.values('name', 'age')
for data in student_data:
print(data['name'], data['age'])
(2)values_list()
-
返回一个可迭代的元祖序列
-
values_list()
方法返回一个可迭代的元组序列,每个元组表示一个查询结果对象,并且元组的元素顺序与指定的字段顺序一致。 -
你可以使用
values_list()
方法指定要获取的字段,也可以使用其他查询方法进行过滤、排序等操作。 -
示例代码:
python# 获取学生表中所有学生的姓名和年龄
student_data = Student.objects.values_list('name', 'age')
for data in student_data:
print(data[0], data[1])
【3】返回具体对象的
(1)get()
-
get()
方法用于获取符合查询条件的单个对象。 -
如果查询结果为空或者超过一个对象符合查询条件,
get()
方法会抛出MultipleObjectsReturned
或者DoesNotExist
异常。 -
你可以使用其他查询方法或者查询参数来限定查询条件。
-
示例代码:
python# 获取名字为 "John" 的学生对象 student = Student.objects.get(name="John")
(2)first()
-
first()
方法用于获取查询结果中的第一个对象,如果查询结果为空,则返回None
。 -
你可以使用其他查询方法或者查询参数来限定查询条件。
-
示例代码:
python# 获取学生表中的第一个学生对象
student = Student.objects.first()
(3)last()
last()
方法用于获取查询结果中的最后一个对象,如果查询结果为空,则返回None
。- 你可以使用其他查询方法或者查询参数来限定查询条件。
python# 获取学生表中的最后一个学生对象
student = Student.objects.last()
【4】返回布尔值的方法:
exists()
-
在Django的QuerySet中,
exists()
是一个返回布尔值的方法,它用于检查查询结果是否存在。 -
exists()
方法的作用是判断查询结果集中是否存在符合给定查询条件的对象。- 如果存在至少一个匹配的对象,则
exists()
方法返回True
- 否则返回
False
。
- 如果存在至少一个匹配的对象,则
-
示例代码:
# 检查名字为 "John" 的学生是否存在
student_exists = Student.objects.filter(name="John").exists()
if student_exists:
print("名字为 John 的学生存在")
else:
print("名字为 John 的学生不存在")
注意事项:
exists()
方法只是检查查询结果中是否有对象存在,并不会实际获取这些对象的数据。- 使用
exists()
方法可以避免将整个查询结果集加载到内存中,因此在性能方面更加高效。- 你可以在任何基于 QuerySet 的查询中都使用
exists()
方法。
【5】返回数字的方法
count()
在使用Django进行数据库查询时,我们通常会首先获取一个QuerySet对象,然后可以对该对象进行过滤、排序等操作。
count()
方法可以用于获取符合查询条件的结果数量,而无需获取实际的数据记录。这对于在不需要获取所有数据的情况下,仅仅需要知道匹配的结果数量非常有用。
-
count()
方法是Django中QuerySet对象的方法。 -
它用于获取满足查询条件的记录数量。
-
通过调用
count()
方法,可以避免获取所有记录,只获取满足条件的记录数量。 -
使用
count()
方法可以快速获取满足查询条件的记录数量,可以用于在Django项目中进行数据统计、结果分页等操作。 -
示例
from myapp.models import MyModel
# 获取所有满足条件的记录数量
count = MyModel.objects.filter(some_field='some_value').count()
print(count) # 输出匹配条件的记录数量
【6】案例演示
-
假设我们有一个学生表(Student)存储了学生的信息,包括姓名(name)、年龄(age)和成绩(score)。
-
首先,我们引入模型和创建几条学生记录作为示例:
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=50)
age = models.IntegerField()
score = models.FloatField()
# 创建几个学生记录
Student.objects.create(name='Alice', age=18, score=90)
Student.objects.create(name='Bob', age=20, score=85)
Student.objects.create(name='Charlie', age=19, score=92)
Student.objects.create(name='David', age=22, score=88)
(1)返回QuerySet对象的方法
- 使用 all() 方法返回所有学生记录:
all_students = Student.objects.all()
- 使用 filter() 方法筛选年龄大于等于20的学生记录:
filtered_students = Student.objects.filter(age__gte=20)
- 使用 exclude() 方法排除成绩小于90的学生记录:
excluded_students = Student.objects.exclude(score__lt=90)
- 使用 order_by() 方法按照成绩降序排序学生记录:
ordered_students = Student.objects.order_by('-score')
- 使用 reverse() 方法反转学生记录的顺序:
reversed_students = Student.objects.reverse()
- 使用 distinct() 方法获取具有不重复姓名的学生记录:
distinct_names = Student.objects.distinct('name')
(2)特殊的QuerySet
特殊的QuerySet方法
values()
和values_list()
提供了以特定格式返回查询结果的功能。
values()
方法返回一个可迭代的字典序列,每个字典对应查询结果中的一条记录,字典的键是字段名,值是字段的值。这个方法可以用于获取指定字段的值,或者用于进行进一步处理和分析。
- 示例代码如下:
students = Student.objects.values('name', 'age', 'score')
for student in students:
print(student['name'], student['age'], student['score'])
- 以上代码会打印出每个学生记录的姓名、年龄和成绩。
values_list()
方法返回一个可迭代的元组序列,每个元组对应查询结果中的一条记录,元组的元素是按照字段在查询中的顺序排列的。这个方法可以用于获取指定字段的值,并且可以选择只获取单个字段的值。
- 示例代码如下:
students = Student.objects.values_list('name', 'age', 'score')
for student in students:
print(student[0], student[1], student[2])
- 以上代码会打印出每个学生记录的姓名、年龄和成绩。
(3)返回具体对象
在 Django 的 QuerySet 中,我们可以使用
get()
、first()
和last()
方法来返回具体的对象。
get()
方法用于获取满足查询条件的单个对象。如果查询结果为空或者超过一个对象,则会引发MultipleObjectsReturned
或DoesNotExist
异常。你可以在查询中使用筛选条件来获取特定的对象。
示例代码如下:
student = Student.objects.get(name='Alice')
print(student.name, student.age, student.score)
以上代码将返回名为 "Alice" 的学生对象,并打印出其姓名、年龄和成绩。
first()
方法用于获取查询结果集中的第一个对象。如果查询结果集为空,则返回None
。
- 示例代码如下:
student = Student.objects.first()
if student:
print(student.name, student.age, student.score)
- 以上代码将返回查询结果集中的第一个学生对象,并打印出其姓名、年龄和成绩。
last()
方法用于获取查询结果集中的最后一个对象。如果查询结果集为空,则返回None
。
- 示例代码如下:
student = Student.objects.last()
if student:
print(student.name, student.age, student.score)
- 以上代码将返回查询结果集中的最后一个学生对象,并打印出其姓名、年龄和成绩。
(4)返回布尔值的方法:
在许多编程语言和框架中,包括 Django,我们经常需要判断某个条件是否成立,返回一个布尔值以表示条件的真假。在 Django 的 QuerySet 中,我们可以使用
exists()
方法来检查查询结果是否存在。
exists()
方法用于检查查询结果集中是否至少存在一个对象。如果存在满足查询条件的对象,则返回 True;否则返回 False。
- 示例代码如下:
# 检查是否存在年龄大于等于18岁的学生
if Student.objects.filter(age__gte=18).exists():
print("存在年龄大于等于18岁的学生")
else:
print("不存在年龄大于等于18岁的学生")
# 检查是否存在姓名为Alice的学生
if Student.objects.filter(name='Alice').exists():
print("存在姓名为Alice的学生")
else:
print("不存在姓名为Alice的学生")
- 以上代码会根据查询结果输出相应的信息。
(5)返回数字的方法有
在编程中,我们常常需要计算某个集合中元素的数量。在许多编程语言和框架中,包括 Django,我们可以使用
count()
方法来返回集合中元素的数量。
在 Django 的 QuerySet 中,count()
方法用于返回查询结果集中对象的数量。
示例代码如下:
# 统计学生表中的学生数量
student_count = Student.objects.count()
print("学生数量:", student_count)
# 统计年龄大于等于18岁的学生的数量
adult_student_count = Student.objects.filter(age__gte=18).count()
print("年龄大于等于18岁的学生数量:", adult_student_count)
以上代码会分别统计学生表中的学生数量和年龄大于等于18岁的学生数量,并输出结果。
通过使用 count()
方法,我们可以方便地获得集合中元素的数量,并进行后续的处理和逻辑判断。
【十五】Django终端打印SQL语句
修改配置
- 如果你想知道你对数据库进行操作时,Django内部到底是怎么执行它的sql语句时可以加下面的配置来查看
- 在Django项目的settings.py文件中,在最后复制粘贴如下代码:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
- 配置好之后,再执行任何对数据库进行操作的语句时,会自动将Django执行的sql语句打印到pycharm终端上
补充:
- 除了配置外,还可以通过一点.query即可查看查询语句,具体操作如下:
【十六】单表查询之神奇的双下划线
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and
类似的还有:startswith,istartswith, endswith, iendswith
date字段还可以:
models.Class.objects.filter(first_day__year=2017)
date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据
# date
#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)
# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)
# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)
# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)
需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~
【十七】聚合查询和分组查询
【1】聚合(利用聚合函数)
aggregate()
是QuerySet
的一个终止子句,意思是说,它返回一个包含一些键值对的字典。- 键的名称是聚合值的标识符,值是计算出来的聚合值。
- 键的名称是按照字段和聚合函数的名称自动生成出来的。
- 用到的内置函数:
from django.db.models import Avg, Sum, Max, Min, Count
- 示例:
>>> from django.db.models import Avg, Sum, Max, Min, Count
>>> models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}
- 如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
>>> models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}
- 如果你希望生成不止一个聚合,你可以向
aggregate()
子句中添加另一个参数。 - 所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
【2】分组
- 我们在这里先复习一下SQL语句的分组。
- 假设现在有一张公司职员表:
- 我们使用原生SQL语句,按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept;
- ORM查询:
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
这里需要注意的是annotate分组依据就是他前面的值,
如果前面没有特点的字段,则默认按照ID分组,
这里有dept字段,所以按照dept字段分组
- 连表查询的分组:
- SQL查询:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
- ORM查询:
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
【3】更多示例
- 示例1:统计每一本书的作者个数
>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
... print(obj.author_num)
...
1
- 示例2:统计出每个出版社买的最便宜的书的价格
>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
... print(obj.min_price)
...
9.90
19.90
方法二:
models.Book.objects.values("publisher__name").annotate(min_price=Min("price")) <QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>
- 示例3:统计不止一个作者的图书
models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
<QuerySet [<Book: 番茄物语>]>
- 示例4:根据一本图书作者数量的多少对查询集
QuerySet
进行排序
models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
<QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>
- 示例5:查询各个作者出的书的总价格
models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
<QuerySet [{'name': '小精灵', 'sum_price': Decimal('9.90')}, {'name': '小仙女', 'sum_price': Decimal('29.80')}, {'name': '小魔女', 'sum_price': Decimal('9.90')}]>
【4】总结
- value里面的参数对应的是sql语句中的select要查找显示的字段,
- filter里面的参数相当于where或者having里面的筛选条件
- annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值