在笔记(三)创建数据库模型对象时提到,每一个模型类都必须继承models.Model,这决定了每个模型类都会有一个继承下来的objects对象,这个对象叫管理器对象,模型类对应数据表的增删改查均可以通过该模型的管理器实现。
django的ORM框架允许我们将数据库表的数据实例化为具体的python对象,即数据库表的每一条记录在django中都对应着一个我们创建的模型类实例化的对象。
创建数据的两种方式:
MyModel.objects.create(属性1=值1,属性2=值2,...)
成功:返回创建好的实体对象
失败:抛出异常
obj = Mymodel(属性1=值1,属性2=值2...)
# 或者单独设置属性,如obj.属性=值
obj.save()
以笔记(三)中bookstore应用下的模型类Book为例,两种方式创建一条数据的代码如下:
# 方法一
book1 = Book.objects.create(title='django教程', pub='工业出版社', price=30, market_price=25)
# 方法二
book2 = Book()
book2.title = 'python教程'
book2.pub='清华大学出版社'
book2.price=70
book2.market_price=60
book2.save()
对于数据表中数据的操作,在django的ORM框架中,均通过模型类继承的objects对象完成,数据的创建即增操作,两种方式已介绍完成。
使用MyModel.objects管理器方法完成,下面对objects的几种方法做介绍
方法 | 说明 |
---|---|
all() | 查询全部记录,返回QuerySet对象 |
get() | 查询符合条件的单一对象 |
filter() | 查询符合条件的多个对象 |
exclude | 查询符合条件之外的全部记录 |
values | 查询部分列的数据并返回QuerySet对象,QuerySet内存字典 |
values_list | 与values类似,返回QuerySet对象,QuerySet内存元组 |
order_by | 对查询结果按某个字段排序 |
方法详解:
from bookstore.models import Book
books = Book.objects.all()
for book in books:
print('书名:', book.title, '出版社:', book.pub)
from bookstore.models import Book
books = Book.objects.filter(pub='清华大学出版社')
for book in books:
print('书名:', book.title)
针对非等值查询,例如数据库中的where price > 30等,django提供了一些查询谓词与objects.filter()方法配合使用,以笔记(三)中应用bookstore下的Author类为例,具体说明如下:
查询谓词 | 谓词说明 | 示例 | 示例说明 |
---|---|---|---|
__exact | 等值匹配 | Author.objects.filter(id__exact=1) | 查询id为1的对象 |
__gt | 大于指定值 | Author.objects.filter(age__gt=50) | 查询年龄大于50的人 |
__gte | 大于等于 | 同__gt | |
__lt | 小于 | 同__gt | |
__lte | 小于等于 | 同__gt | |
__in | 查找数据是否在指定范围内 | Author.objects.filter(country__in=[‘中国’, ‘美国’]) | 查找中国和美国的作者 |
__range | 查找数据是否在指定的区间内 | Author.objects.filter(age__range=(35,40)) | 查找年龄在35-40岁的人 |
__contains | 包含指定值 | Author.objects.filter(name__contains=‘x’) | 等同于sql中的like语句 |
__startswith | 以XXX开始 | Author.objects.filter(name__startswith=‘王’) | 查询姓王的作者 |
__endswith | 以XXX结束 | Author.objects.filter(name__startswith=‘羽’) | 名字最后一个字为‘羽’的人 |
关于数据查询中QuerySet的其他用法,参考官方文档
QuerySet API 参考
数据的更新可分为两种,一种是对单个数据的修改,一种是批量修改数据,具体介绍如下
更新单个数据步骤:
# 单个数据修改
# 将id为1的书价格改为30
book = Book.objects.get(id=1)
book.price = 30
book.save()
批量数据更新:
直接调用QuerySet的update(属性=值),实现批量修改数据
# 将id大于2的图书价格改为30
books = Book.objects.filter(id__gt=2)
books.update(price=30)
与数据更新相似,数据删除也分为单个记录删除和批量数据删除
单个数据删除:
批量数据删除:
# 单个删除,删除id为1的作者信息
try:
author = Author.objects.get(id=1)
author.delete()
except:
print('删除失败')
# 批量删除年龄不小于60岁的作者信息
authors = Author.objects.filter(age__gte=60)
authors.delete()
代表数据库中某条记录的字段信息
作用:
form django.db.models import F
# 将所有书的价格上调10元
Book.objects.all().update(price=F('price')+10)
上述例子中,直接对price加10,而不是先获取price再加10的,减少了一部分开销
用于实现逻辑或‘|’、逻辑‘&’、逻辑非‘~’等操作
from django.db.models import Q
# 找出工业出版社出版的价格或者价格不高于100元的书籍
Book.objects.filter(Q(pub='工业出版社')|Q(price__lte=100))
在使用Q对象时,可组合‘&’、‘|’、‘&’使用以完成更为复杂的逻辑
聚合查询分为整表聚合和分组聚合
对全部数据集中统计查询,需要导入方法:
聚合函数 | 说明 |
---|---|
Sum | 求和 |
Avg | 求均值 |
Count | 计数 |
Max | 求最大值 |
Min | 求最小值 |
语法:MyMode.objects.aggregate(结果变量名=聚合函数(‘列’))
返回结果是结果变量名与值组成的字典,即{‘变量名’, ‘值’}
示例:在django Shell演示下获取书本数量
在查询值的基础上聚合,即对查询返回的QuerySet容器使用聚合
语法:QuerySet.annotate(结果变量名=聚合函数(‘列’))
返回值:QuerySet容器
# 首先得到要分组聚合的列(出版社)
pub_set = Book.objects.value('pub')
# 按照所得列,计算各出版社出版的书本数量
pub_set_num = pub_set.annotate(booknum=Count('pub'))
同样在django Shell下演示,结果如下:
关于聚合使用的其他操作,django官方文档上也有详细的说明,使用时作为工具文档查询:聚合
django同样支持直接使用sql语句查询,但是这是django不提倡的,在我的学习过程中,只简单了解了两种基本方法。
使用objects.raw()方法进行数据库查询
语法:MyModel.objects.raw(sql语句, 拼接参数)
返回值:RawQuerySet集合,只支持基本的操作,例如循环,不能像QuerySet一样使用聚合,update等方法。
books = Book.objects.raw('select * from book')
for book in books:
print(book)
这种方法使用django.db下connection包中的cursor类,通过cursor对象操作数据库。
from django.db import connection
with connection.cursor() as cur:
cur.execute('update book set pub="清华大学出版社" where id=1;')
为保证在出现异常时能释放cursor对象,通常使用with语句创建操作
关于django更深入的原生SQL使用,参考官方文档:执行原生 SQL 查询