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做量化投资系列之比特币初始配置
Jan 23 Python
Django之创建引擎索引报错及解决详解
Jul 17 Python
python 定时器每天就执行一次的实现代码
Aug 14 Python
python网络编程之多线程同时接受和发送
Sep 03 Python
Python 文件操作之读取文件(read),文件指针与写入文件(write),文件打开方式示例
Sep 29 Python
Python 脚本拉取 Docker 镜像问题
Nov 10 Python
python爬虫模拟浏览器的两种方法实例分析
Dec 09 Python
解决Tensorboard 不显示计算图graph的问题
Feb 15 Python
python 递归调用返回None的问题及解决方法
Mar 16 Python
python数据库开发之MongoDB安装及Python3操作MongoDB数据库详细方法与实例
Mar 18 Python
python3 googletrans超时报错问题及翻译工具优化方案 附源码
Dec 23 Python
Python实现简单的俄罗斯方块游戏
Sep 25 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中防止恶意刷新页面的代码小结
2012/10/31 PHP
Linux系统递归生成目录中文件的md5的方法
2015/06/29 PHP
php array_values 返回数组的值实例详解
2016/11/17 PHP
php + ajax 实现的写入数据库操作简单示例
2020/05/16 PHP
php中array_fill函数的实例用法
2021/03/02 PHP
Jquery操作Select 简单方便 一个js插件搞定
2009/11/12 Javascript
stream.js 一个很小、完全独立的Javascript类库
2011/10/28 Javascript
js获取某元素的class里面的css属性值代码
2014/01/16 Javascript
jQuery新的事件绑定机制on()示例应用
2014/07/18 Javascript
jQuery+AJAX实现无刷新下拉加载更多
2015/07/03 Javascript
jQuery对html元素的取值与赋值实例详解
2015/12/18 Javascript
JS判断日期格式是否合法的简单实例
2016/07/11 Javascript
nodejs+mongodb aggregate级联查询操作示例
2018/03/17 NodeJs
Angular-UI Bootstrap组件实现警报功能
2018/07/16 Javascript
jQuery实现为table表格动态添加或删除tr功能示例
2019/02/19 jQuery
vue.js中使用echarts实现数据动态刷新功能
2019/04/16 Javascript
VueQuillEditor富文本上传图片(非base64)
2020/06/03 Javascript
解决vue字符串换行问题(绝对管用)
2020/08/06 Javascript
一文秒懂JavaScript构造函数、实例、原型对象以及原型链
2020/08/25 Javascript
基于JQuery和DWR实现异步数据传递
2020/10/16 jQuery
JavaScript实现复选框全选和取消全选
2020/11/20 Javascript
Python中格式化format()方法详解
2017/04/01 Python
在Python中增加和插入元素的示例
2018/11/01 Python
Python + OpenCV 实现LBP特征提取的示例代码
2019/07/11 Python
PyCharm无法引用自身项目解决方式
2020/02/12 Python
python统计函数库scipy.stats的用法解析
2020/02/25 Python
分享一枚pycharm激活码适用所有pycharm版本我的pycharm2020.2.3激活成功
2020/11/20 Python
canvas学习笔记之绘制简单路径
2019/01/28 HTML / CSS
考试没考好检讨书
2014/01/31 职场文书
搞笑征婚广告词
2014/03/17 职场文书
环保标语大全
2014/06/12 职场文书
农民工工资保障承诺书
2015/05/04 职场文书
汤姆叔叔的小屋读书笔记
2015/06/30 职场文书
php 原生分页
2021/04/01 PHP
一文搞懂php的垃圾回收机制
2021/06/18 PHP
Python使用socket去实现TCP客户端和TCP服务端
2022/04/12 Python