Django学习笔记(四)

模型层(二)

  • 一、管理器对象与数据的创建
    • 1. 管理器对象
    • 2. 创建数据
  • 二、数据增删改查
    • 1. 数据查询
    • 2. 查询谓词
    • 3. 数据更新
    • 4. 数据删除
  • 三、F对象与Q对象
    • 1. F对象
    • 2. Q对象
  • 四、聚合查询
    • 1. 整表聚合
    • 2. 分组聚合
  • 五、原生数据库操作
    • 1. 通过管理器使用sql
    • 2. 不使用模型类,直接操作数据库

一、管理器对象与数据的创建

1. 管理器对象

在笔记(三)创建数据库模型对象时提到,每一个模型类都必须继承models.Model,这决定了每个模型类都会有一个继承下来的objects对象,这个对象叫管理器对象,模型类对应数据表的增删改查均可以通过该模型的管理器实现。

2. 创建数据

django的ORM框架允许我们将数据库表的数据实例化为具体的python对象,即数据库表的每一条记录在django中都对应着一个我们创建的模型类实例化的对象。

创建数据的两种方式:

  1. 方法一 直接创建实体对象
MyModel.objects.create(属性1=1,属性2=2,...)

成功:返回创建好的实体对象
失败:抛出异常

  1. 方法二 先创建对象,再保存
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对象完成,数据的创建即增操作,两种方式已介绍完成。

1. 数据查询

使用MyModel.objects管理器方法完成,下面对objects的几种方法做介绍

方法 说明
all() 查询全部记录,返回QuerySet对象
get() 查询符合条件的单一对象
filter() 查询符合条件的多个对象
exclude 查询符合条件之外的全部记录
values 查询部分列的数据并返回QuerySet对象,QuerySet内存字典
values_list 与values类似,返回QuerySet对象,QuerySet内存元组
order_by 对查询结果按某个字段排序

方法详解:

  • all()方法:
    用法:MyModel.objects.all(),等同于select * from table
    返回值:QuerySet容器对象,内部存放MyModel实例
from bookstore.models import Book
    books = Book.objects.all()
    for book in books:
        print('书名:', book.title, '出版社:', book.pub)
  • values(‘列1’,‘列2’,…)
    用法:MyModel.objects.values(…),等同于select 列1, 列2 from table
    返回值:QuerySet容器,容器内存字典,格式为{‘列1’:值1, ‘列2’:值2}
  • values_list(‘列1’,‘列2’,…)
    用法:与values相同
    返回值:QuerySet容器,容器内部存储元组,数据封装为元组后再封装至QuerySet中
  • order_by()
    用法:MyModel.objects.order_by(’-列’, ‘列’)
    返回值:QuerySet容器,与all()不同,根据指定字段对查询结果排序,默认为升序,若需要降序,在列前增加’-’
  • filter(条件)
    用法:MyModel.objects.filter(属性1=值1,属性2=值2…),即条件查询
    返回值:QuerySet容器对象,内部存放MyModel实例对象
    注意:同时筛选多个属性,为“与”关系
from bookstore.models import Book
	books = Book.objects.filter(pub='清华大学出版社')
	for book in books:
    	print('书名:', book.title)
  • exclude(条件)
    用法:MyModel.objects.exclude(属性1=值1,属性2=值2)
    返回值:QuerySet容器,内部存放MyModel实例对象
  • get(条件)
    用法:MyModel.objects.get(条件)
    返回值:返回满足条件的唯一一条数据
    若查询结果多于一条则抛出Model.MultipleObjectsReturned异常,若没有数据则抛出Model.DoesNoteExist异常

2. 查询谓词

针对非等值查询,例如数据库中的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 参考

3. 数据更新

数据的更新可分为两种,一种是对单个数据的修改,一种是批量修改数据,具体介绍如下

更新单个数据步骤:


  1. 通过get()得到要修改的实体对象

  2. 通过对象.属性的方式更改数据

  3. 使用save()方法保存数据
# 单个数据修改
# 将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)

4. 数据删除

与数据更新相似,数据删除也分为单个记录删除和批量数据删除

单个数据删除:

  1. 根据条件查找一个数据对象
  2. 调用对象的delete()方法删除

批量数据删除:

  1. 查找满足条件的全部QuerySet集合对象
  2. 调用集合对象QuerySet的delete()方法删除
# 单个删除,删除id为1的作者信息
try:
	author = Author.objects.get(id=1)
	author.delete()
except:
	print('删除失败')

# 批量删除年龄不小于60岁的作者信息
authors = Author.objects.filter(age__gte=60)
authors.delete()

三、F对象与Q对象

1. F对象

代表数据库中某条记录的字段信息

作用:

  • 对数据库中的字段在不获取的情况下操作
  • 用于类属性(字段)的比较
    用法:F(列名)
form django.db.models import F
# 将所有书的价格上调10元
Book.objects.all().update(price=F('price')+10)

上述例子中,直接对price加10,而不是先获取price再加10的,减少了一部分开销

2. Q对象

用于实现逻辑或‘|’、逻辑‘&’、逻辑非‘~’等操作

from django.db.models import Q
# 找出工业出版社出版的价格或者价格不高于100元的书籍
Book.objects.filter(Q(pub='工业出版社')|Q(price__lte=100))

在使用Q对象时,可组合‘&’、‘|’、‘&’使用以完成更为复杂的逻辑

四、聚合查询

聚合查询分为整表聚合和分组聚合

1. 整表聚合

对全部数据集中统计查询,需要导入方法:

聚合函数 说明
Sum 求和
Avg 求均值
Count 计数
Max 求最大值
Min 求最小值

语法:MyMode.objects.aggregate(结果变量名=聚合函数(‘列’))
返回结果是结果变量名与值组成的字典,即{‘变量名’, ‘值’}

示例:在django Shell演示下获取书本数量

计算书本数量

2. 分组聚合

在查询值的基础上聚合,即对查询返回的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不提倡的,在我的学习过程中,只简单了解了两种基本方法。

1. 通过管理器使用sql

使用objects.raw()方法进行数据库查询

语法:MyModel.objects.raw(sql语句, 拼接参数)
返回值:RawQuerySet集合,只支持基本的操作,例如循环,不能像QuerySet一样使用聚合,update等方法。

books = Book.objects.raw('select * from book')
for book in books:
	print(book)

2. 不使用模型类,直接操作数据库

这种方法使用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 查询

你可能感兴趣的:(Django学习,django)