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实现的石头剪子布代码分享
Aug 22 Python
Python中生成Epoch的方法
Apr 26 Python
matplotlib设置legend图例代码示例
Dec 19 Python
python使用json序列化datetime类型实例解析
Feb 11 Python
Python 打印中文字符的三种方法
Aug 14 Python
Python3几个常见问题的处理方法
Feb 26 Python
python和mysql交互操作实例详解【基于pymysql库】
Jun 04 Python
Django 反向生成url实例详解
Jul 30 Python
python Popen 获取输出,等待运行完成示例
Dec 30 Python
python实现控制台输出彩色字体
Apr 05 Python
python 使用建议与技巧分享(四)
Aug 18 Python
如何用 Python 制作 GitHub 消息助手
Feb 20 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版自动生成文章摘要
2008/07/23 PHP
基于empty函数的输出详解
2013/06/17 PHP
CI框架中zip类应用示例
2014/06/17 PHP
Laravel实现用户注册和登录
2015/01/23 PHP
PHP文件缓存类实现代码
2015/10/26 PHP
yii2.0实现pathinfo的形式访问的配置方法
2016/04/06 PHP
JavaScript 面向对象编程(2) 定义类
2010/05/18 Javascript
分享2个jQuery插件--jquery.fileupload与artdialog
2014/12/26 Javascript
jQuery蓝色风格滑动导航栏代码分享
2015/08/19 Javascript
Bootstrap每天必学之面板
2015/11/30 Javascript
web 前端常用组件之Layer弹出层组件
2016/09/22 Javascript
解决淘宝cnpm 安装后cnpm不是内部或外部命令的问题
2018/05/17 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
2018/10/10 Javascript
基于Vue实现图片在指定区域内移动的思路详解
2018/11/11 Javascript
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
微信小程序HTTP请求从0到1封装
2019/09/09 Javascript
详解Vue3 Composition API中的提取和重用逻辑
2020/04/29 Javascript
理解Python中的类与实例
2015/04/27 Python
Python抓取手机号归属地信息示例代码
2016/11/28 Python
python网络编程调用recv函数完整接收数据的三种方法
2017/03/31 Python
Python 查找字符在字符串中的位置实例
2018/05/02 Python
python numpy和list查询其中某个数的个数及定位方法
2018/06/27 Python
python定时按日期备份MySQL数据并压缩
2019/04/19 Python
Python控制台输出时刷新当前行内容而不是输出新行的实现
2020/02/21 Python
Django通过json格式收集主机信息
2020/05/29 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
一些关于python 装饰器的个人理解
2020/08/31 Python
Python新建项目自动添加介绍和utf-8编码的方法
2020/12/26 Python
Bjorn Borg官方网上商店:国际运动时尚品牌
2016/08/27 全球购物
FORZIERI福喜利中国官网:奢侈品购物梦工厂
2019/05/03 全球购物
什么是SQL Server的确定性函数和不确定性函数
2016/08/04 面试题
关于Assembly命名空间的三个面试题
2015/07/23 面试题
会计专业自荐信范文
2013/12/02 职场文书
李强为自己工作观后感
2015/06/11 职场文书
浅谈spring boot使用thymeleaf版本的问题
2021/08/04 Java/Android
Redis命令处理过程源码解析
2022/02/12 Redis