Python的Django框架实现数据库查询(不返回QuerySet的方法)


Posted in Python onMay 19, 2020

一、创建模型类:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class Course(models.Model):
 """课程表"""
 name = models.CharField(verbose_name='课程名称', max_length=255)
 description = models.TextField(verbose_name='课程描述信息', null=True)
 price = models.DecimalField(verbose_name=u'课程价格', max_digits=15, decimal_places=2, default=0.0)
 deleted = models.BooleanField(verbose_name='课程是否被删除', default=False)
	created_at = models.DateTimeField(auto_now_add=True, db_index=True)
 edited_at = models.DateTimeField(auto_now=True)

 def __repr__(self):
 return self.name

class User(models.Model):
 """用户表:记录用户常用信息"""
 name = models.CharField(verbose_name=u'用户的姓名', max_length=32, null=True)
 mobile = models.CharField(verbose_name=u'用户的手机号', max_length=32, unique=True)
 courses = models.ManyToManyField(verbose_name=u'关联课程', to='Course', through='UserCourse', related_name='user_course')

class UserExtra(models.Model):
 """用户信息额外表: 存储一些用户不常用信息"""
 birthday = models.CharField(verbose_name=u'生日', max_length=32, null=True)
 email = models.EmailField(verbose_name=u'邮箱', null=True)
 user = models.OneToOneField(to=User, related_name='extra') # 跟User表是一对一的关系

class UserCourse(models.Model):
 """课程表跟用户表手动添加的多对多表"""
 course = models.ForeignKey('Course', related_name='my_course')
 user = models.ForeignKey('User', related_name='my_user')

class Coursechapter(models.Model):
 """课程章节表"""
 name = models.CharField(verbose_name='课程名称', max_length=255)
 description = models.TextField(verbose_name='课程描述信息', null=True)
 course = models.ForeignKey('Course', related_name='course_chapter')

执行以下命令,进行数据库的迁移:

python manage.py makemigrations app_name[应用的名称]
python manage.py migrate app_name[应用的名称]

迁移成功后可以进行以下的操作咯~

二、介绍不返回QuerySet的方法:

方法名 介绍
get() 获取单个对象
create() 创建对象
bulk_create() 批量创建对象
get_or_create() 查询对象,若没有找到则创建新的对象
update() 批量更新对象
update_or_create() 更新对象,若没有找到则创建新的对象
delete() 批量删除对象
first() 获取第一个对象
last() 获取最后一个对象
latest() 获取最近的对象
earliest() 获取最早的对象
count() 统计对象的个数
exists() 判断queryset中是否有对象
aggregate() 聚合操作
in_bulk() 根据主键值的列表,批量返回对象
iterator() 获取包含对象的迭代器

三、以上方法的使用:

1.get()方法:

返回按照查询参数匹配到的单个对象,若匹配到的对象个数不只一个的话,会触发MultipleObjectsReturned异常,若根据参数匹配不到对象的时候,会触发DoesNotExist异常。

成功栗子:

try:
 user_obj = models.User.objects.get(mobile=13069636688)
 print(user_obj)
except models.User.DoesNotExist:
 print 'User Not Exist'
# 输出结果:
User object

使用get()方法最好将异常捕获添加上。

获取参数失败栗子:

# 使用get()方法获取一条不存在的数据
user_obj = models.User.objects.get(mobile=13888888888)
# 抛出异常:
DoesNotExist: User matching query does not exist.

# 使用get()方法获取多条数据
user_obj = models.User.objects.get(name='小明')
# 抛出异常:
MultipleObjectsReturned: get() returned more than one User -- it returned 2!

使用ObjectDoesNotExist异常栗子:

DoesNotExist异常从django.core.exceptions.ObjectDoesNotExist继承,可以定位多个DoesNotExist异常,举个栗子:

from django.core.exceptions import ObjectDoesNotExist
try:
 user_obj = models.User.objects.get(mobile=13888888888)
except ObjectDoesNotExist:
 print 'User Not Exist'
# 抛出自定义异常:
User Not Exist

通常我们使用get()方法中的参数,都是查询表中作为唯一标识的字段。

2.create()方法:

create(**kwargs)

在一步操作中同时创建并且保存对象的便捷方法。

举个栗子:

user_obj = models.User.objects.create(mobile=13045621111, name='小牛')
print(user_obj)
# 输出结果如果:
User object

同等于:

user_obj = models.User(mobile=13045621112, name='小牛')
user_obj.save()

3.bulk_create()方法:

bulk_create(objs, batch_size=None)

这种插入比较高效(通常仅一个查询,无论有多少对象),将提供的对象列表插入到数据库中。

举个栗子:

course_obj = models.Course.objects.bulk_create(
 [
 models.Course(name='哈尔滨工业大学'),
 models.Course(name='长春大学')
 ]
)
print course_obj
# 输出结果如下:
[<Course: 哈尔滨工业大学>, <Course: 长春大学>]

注意:

1.不会调用模型的save()方法,所以不会发送pre_save和post_save信号。

2.不适用多张表继承中的子模型。

3.不适用于多对多关系。

4. get_or_create() 方法:

get_or_create(defaults=None, **kwargs)

通过kwargs来查询对象的简便方法(若模型中所有字段都有默认值或可以为空),如果该对象不存在则创建一个新的对象。

该方法返回一个由(object,created)组成的元组,元组中的object是一个查询到或被创建的对象,created是一个表示是否创建新对象的布尔值(true:表示创建新对象|false:相反)。

举个栗子:

try:
 # 通过id=100查看课程是否存在
 course_obj = models.Course.objects.get(pk=100)
except ObjectDoesNotExist:
 # 如果不存在就创建一门课程
 course_obj = models.Course.objects.create(name='上海财经大学', price='1877')

使用get_or_create()方法重写的栗子:

# 查看课程的name="上海交通大学", 如果不存在, 那么创建一条name="信息科技大学",price=2000的数据
obj, created = models.Course.objects\
 .get_or_create(name='上海交通大学',
  defaults={'name': '信息科技大学', 'price': 2000})

print(obj, created)
# 输出结果如下:
Course object True

注意:

​ 1.任何传递给get_or_create()的关键字参数,除了一个可选的defaults,都将传递给get()方法调用。

​ 2.如果找到一个对象,返回一个包含匹配到的对象以及False组成元组。

​ 3.如果查到的对象超过一个以上,将抛出MultipleObjectsReturned异常。

​ 4.如果找不到对象,get_or_create()将会实例化并保存一个新的对象,返回一个由新的对象以及True组成元组。

建议:只在Django视图的POST请求中使用get_or_create(),因为这是一个具有修改性质的动作,不应该使用在GET请求中,那样不安全。

5. update()方法:

update(**kwargs)

对指定的字段执行批量更新操作,并返回匹配的行数

举个栗子:

# 可以更新多个字段,没有多少字段的限制
course_row = models.Course.objects.filter(name='北京大学')\
 .update(name='上海交通大学', price=2000)

print(course_row)
# 输出结果如下:
1 # 表示仅在数据库中修改了一条数据

注意:

​ 1.update()方法无需save()操作,唯一限制是它只能更新模型主表中的列,而不是关联的整个模型。

​ 2.update()方法返回受影响的行数。

​ 3.update()方法还可以防止在加载对象和调用save()之间的短时间内数据库中某些内容可能发生更改的竞争条件。

仅是更新一下对象,不需要为对象做其他事情,最有效的方法是调用update(),而不是将模型对象加载到内存中去。

# 不要这么做的栗子:
course_obj = models.Course.objects.get(name='北京大学')
course_obj.name = '北京大学'
course_obj.save()

6.update_or_create()方法:

update_or_create(defaults=None, **kwargs)

通过给出的kwargs来更新对象的便捷方法, 如果没找到对象,则创建一个新的对象。

defaults是一个由 (field, value)对组成的字典,用于更新对象。defaults中的值可以是可调用对象。

该方法返回一个由(object, created)组成的元组,元组中的object是一个创建的或者是被更新的对象, created是一个标示是否创建了新的对象的布尔值(true(表示创建成功)|false(相反)) 。

举个栗子:

try:
 # 查看课程name="北京大学"存在,若存在那么将name修改成"财经大学"进行保存
 course_obj = models.Course.objects.get(name='北京大学')
 course_obj.name = '财经大学'
 course_obj.save()
except ObjectDoesNotExist:
 # 如果不存在, 则创建一条name="北京大学"的课程
 course_obj = models.Course.objects.create(name='北京大学')

使用update_or_create()方法重写:

# 查找课程name="财经大学"是否存在, 如果存在,将name跟price字段进行更新, 若不存在创建新的记录
obj, res = models.Course.objects\
 .update_or_create(name='财经大学',
  defaults={'name': '复旦大学', 'price': 2080})

print(obj, res)
# 输出结果:
Course object False # 表示没有创建新的对象, 若找到该对象将更新

Course object True # 表示创建了新的对象

7.delete()方法:

delete()

批量删除QuerySet中的所有对象,并返回删除的对象个数和每个对象类型的删除次数的字典。
delete()动作是立即执行的。

举个栗子:

# 删除课程price=2080的所有课程
cur_course =models.Course.objects.filter(price=2080).delete()
print(cur_course)

# 输出结果:
(7, {u'apps.Coursechapter': 2, u'apps.Course': 2, u'apps.UserCourse': 3})
# 分析以上结果, 7表示共删除7条数据, Coursechapter表中2条数据, Course表中2条数据, UserCourse表中3条数据

注意:delete()会为所有已删除的对象(包括级联删除、对象的外键、多对多的关系)发出pre_delete和post_delete信号。

8.first()方法:

first()

返回结果集的第一个对象, 当没有找到时返回None。如果QuerySet没有设置排序,则将会自动按主键进行排序。

举个栗子:

# 获取课程表所有数据中的第一条数据
course_obj = models.Course.objects.all().first()
print(course_obj)
# 输出结果如下:
Course object # 说明获取到了第一条数据

# 获取课程name='农业大学'的第一条数据
course_obj = models.Course.objects.filter(name='农业大学').first()
print(course_obj)
# 输出结果:
None # 说明课程表中没有name='农业大学'

使用[0]来获取第一个对象:

course_obj = models.Course.objects.filter(name='农业大学')[0]
print(course_obj)
# 输出结果:
IndexError: list index out of range # 抛出异常,没有找到并不会返回None

# 如果使用[0]方法,需要添加异常处理
try:
 course_obj = models.Course.objects.filter(name='农业大学')[0]
except IndexError:
 course_obj = None

9.last()方法:

last()

跟first()方法相同,只是返回的是查询集中最后一个对象。

举个栗子:

# 获取课程表中最后一条数据
course_obj = models.Course.objects.last()
print(course_obj)
# 输出结果:
Course object

10.latest()方法:

latest(field_name=None)

使用日期字典field_name,按日期返回最新对象。

举个栗子:

# 查看按创建课程日前返回的最新对象
course_obj = models.Course.objects.filter(created_at__isnull=False).latest('created_at')
print(course_obj.id)
# 输出结果:
101 # 这次是打印的Course表的ID,因为创建课程时, 这就是创建的最新对象。

注意:earliest()和latest()可能会返回空日期的实例,可能需要过滤掉空值 。

11.earliest()方法:

earliest(field_name=None)

跟latest()方法相同,只是返回查询集中按日期最早的对象。

举个栗子:

# 获取课程表中按日期创建课程最早的对象
course_obj = models.Course.objects.filter(created_at__isnull=False).earliest('created_at')
print(course_obj.id)
# 输出结果:
1 # 打印Course表中的ID,因为数据库第一条数据,就是最早创建的

12.count()方法:

count()

返回在数据库中对应的QuerySet对象的个数。

举个栗子:

course_count = models.Course.objects.all().count()
print(course_count)
# 输出结果:

count()永远不会引发异常。

13.exists()方法:

exists()

如果QuerySet包含任何结果,则返回True,否则返回False。

举个栗子:

# 查找课程表中是否包含name="信息科技大学的集合"
course_list = models.Course.objects.filter(name='信息科技大学')
# 如果存在就打印"存在"
if course_list.exists():
 print('存在')
# 输出结果:
存在

该exists()方法快于以下栗子:

# 同样查找课程中是否包含name="信息科技大学"
course_list = models.Course.objects.filter(name='信息科技大学')
if course_list:
 print('存在')
# 输出结果:
存在

14.aggregate()方法:

aggregate(args, *kwargs)

返回汇总值的字典(平均值、总和等),通过QuerySet进行计算,每个参数指定返回的字典中将要包含的值。

举个栗子:

匿名参数的名称将基于聚合函数的名称和模型字段生成

from django.db.models import Count

# 获取课程名称name="信息科技大学",将"name"字段进行聚合统计
course_dict = models.Course.objects.filter(name="信息科技大学").aggregate(Count('name'))
print(course_dict)
# 输出结果:
{u'name__count': 3} # 将基于聚合函数的名称(count)和模型字段(name)生成

再举个栗子:

使用关键字参数来指定聚合函数,可以控制返回的聚合的值的名称。

from django.db.models import Count

# 获取课程名称name="信息科技大学", 将name字段进行聚合统计
course_dict = models.Course.objects.filter(name="信息科技大学")\
 .aggregate(customize_name=Count('name'))
print(course_dict)
# 输出结果:
{'customize_name': 3} # 使用关键字参数指定聚合函数,返回聚合的值名称

15.in_bulk()方法:

in_bulk(id_list=None)

获取主键值的列表,并返回将每个主键值映射到具有给定ID的对象的实例的字典。如果未提供列表,则会返回查询集中所有对象。

举个栗子:

# 获取课程表中ID是1的对象
course_obj = models.Course.objects.in_bulk([1])
print(course_obj)
# 输出结果:
{1: <Course: Course object>}

# 获取课程表中ID是2,3的对象
course_obj = models.Course.objects.in_bulk([2, 3])
print(course_obj)
# 输出结果:
{2: <Course: Course object>, 3: <Course: Course object>}

# 若列表中没有填写ID, 返回空字典
course_obj = models.Course.objects.in_bulk([])
print(course_obj)
# 输出结果:
{}

# 获取课程表所有的ID对应的对象, 返回一个字典
course_obj = models.Course.objects.in_bulk()
print(course_obj)
# 输出结果:
{1: <Course: Course object>, 2: <Course: Course object>, 3: <Course: Course object>, 4: <Course: Course object>, 5: <Course: Course object>, 6: <Course: Course object>,

16.iterator()方法:

iterator()

提交数据库操作,获取QuerySet,返回一个迭代器。

QuerySet通常会再内部缓存其结果,以便再重复计算时不会导致额外的查询。

主要时QuerySet的缓存机制,如果一次从数据库取出很多数据,就有可能导致程序崩溃,可以利用iterator()方法,做性能优化。

举个栗子:

# 取出数据库的所有对象, 要考虑cache机制, 如果数据量太大, 程序就会崩溃
course_list = models.Course.objects.all()

# 利用iterator()方法, 这次就不能用2次for循环, 第一次for循环, 就已经遍历完了
course_set = models.Course.objects.all().iterator()
print(next(course_set))
print(next(course_set))
print(next(course_set))

# 对数据库进行更新, 但并没有执行, 只有再用的时候再执行
models.Course.objects.filter(pk=1).update(price=66)


# 如果for循环2次, 打印2次结果, 也是执行一次sql语句,因为存在sql缓存机制,
# 把第一次查询的结果放到缓存里, 下次从缓存里调
for obj in course_list:
 print(obj.name, obj.price)

"""
# 更新数据之前
id:1
name: 上海交通大学
price: 2000
# 更新数据后
id:1 
name: 上海交通大学
price : 66
"""

使用iterator()会导致先前的prefetch_related()调用被忽略,因为这两个一起优化没有意义。

以上这篇Python的Django框架实现数据库查询(不返回QuerySet的方法)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用Python实现一个简单的能够发送带附件的邮件程序的教程
Apr 08 Python
Python实现约瑟夫环问题的方法
May 03 Python
Python金融数据可视化汇总
Nov 17 Python
Python3导入自定义模块的三种方法详解
Apr 13 Python
基于Python实现迪杰斯特拉和弗洛伊德算法
May 27 Python
python字典嵌套字典的情况下找到某个key的value详解
Jul 10 Python
Python判断字符串是否xx开始或结尾的示例
Aug 08 Python
Django多进程滚动日志问题解决方案
Dec 17 Python
Python Pandas数据分析工具用法实例
Nov 05 Python
OpenCV-Python实现图像平滑处理操作
Jun 08 Python
在Python 中将类对象序列化为JSON
Apr 06 Python
python语言中pandas字符串分割str.split()函数
Aug 05 Python
django 数据库返回queryset实现封装为字典
May 19 #Python
使用PyQt的QLabel组件实现选定目标框功能的方法示例
May 19 #Python
python 数据分析实现长宽格式的转换
May 18 #Python
如何把外网python虚拟环境迁移到内网
May 18 #Python
python 实现 hive中类似 lateral view explode的功能示例
May 18 #Python
pandas dataframe 中的explode函数用法详解
May 18 #Python
Python pandas 列转行操作详解(类似hive中explode方法)
May 18 #Python
You might like
php防盗链的常用方法小结
2010/07/02 PHP
PHP的变量类型和作用域详解
2014/03/12 PHP
ThinkPHP模板判断输出Empty标签用法详解
2014/06/30 PHP
PHP+MYSQL中文乱码问题
2015/07/01 PHP
PHP闭包函数详解
2016/02/13 PHP
php curl常用的5个经典例子
2017/01/20 PHP
Codeigniter里的无刷新上传的实现代码
2019/04/14 PHP
Yii框架的路由配置方法分析
2019/09/09 PHP
PHP实现计算器小功能
2020/08/28 PHP
Aster vs Newbee BO5 第三场2.19
2021/03/10 DOTA
JavaScript 一行代码,轻松搞定浮动快捷留言-V2升级版
2010/04/02 Javascript
javascript 正则表达式相关应介绍
2012/11/27 Javascript
文本框中禁止非数字字符输入比如手机号码、邮编
2013/08/19 Javascript
ajax读取数据后使用jqchart显示图表的方法
2015/06/10 Javascript
简述JavaScript中正则表达式的使用方法
2015/06/15 Javascript
JavaScript脚本判断蜘蛛来源的方法
2015/09/22 Javascript
AngularJS实践之使用ng-repeat中$index的注意点
2016/12/22 Javascript
ReactNative 之FlatList使用及踩坑封装总结
2017/11/29 Javascript
JS运动特效之同时运动实现方法分析
2018/01/24 Javascript
javascript网页随机点名实现过程解析
2019/10/15 Javascript
Nodejs环境实现socket通信过程解析
2020/07/03 NodeJs
移动端JS实现拖拽两种方法解析
2020/10/12 Javascript
微信小程序实现页面监听自定义组件的触发事件
2020/11/01 Javascript
[45:52]2018DOTA2亚洲邀请赛 4.1小组赛 A组加赛 LGD vs Liquid
2018/04/02 DOTA
Python中的闭包实例详解
2014/08/29 Python
python 简单的多线程链接实现代码
2016/08/28 Python
python实现简单名片管理系统
2018/11/30 Python
python 多个参数不为空校验方法
2019/02/14 Python
python邮件中附加文字、html、图片、附件实现方法
2021/01/04 Python
美国最大网上鞋店:Zappos
2016/07/25 全球购物
介绍一下Java中的static关键字
2012/05/12 面试题
校长一岗双责责任书
2015/05/09 职场文书
服装店员工管理制度
2015/08/07 职场文书
承诺书怎么写 ?
2019/04/16 职场文书
深度学习详解之初试机器学习
2021/04/14 Python
GPU服务器的多用户配置方法
2022/07/07 Servers