Python的Django框架实现数据库查询(不返回QuerySet的方法)
作者:Fe_cow丿
一、创建模型类:
# -*- 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的方法)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。