P08 QuerySet 和 Instance

QuerySet

Django 的 ORM(Object-Relational Mapping,对象-关系映射)是一个非常强大的工具,它帮助你管理和查询数据库。ORM 能够让你使用Python(或其他编程语言)来操作数据库,就像你在操作Python对象一样。ORM用到三个类:Manager、QuerySet、Model。

从数据库中查询出来的结果一般是一个集合,这个集合叫做 QuerySet。

Django的ORM通过Model的objects属性提供各种数据操的接口(API),并通过 Model.objects 方法返回QuerySet,生产符合查询条件的列表,列表中包含多个 Instance。

QuerySet 的正式定义

class QuerySet(model=None, query=None, using=None)[source]

QuerySet 的两大特色

(1) 惰性:若这个对象中包含了需要的数据且需要使用时,它会去DB中获取数据,否则不会获取。 比如说在内部,创建、 过滤、切片和传递一个QuerySet,而没有进行真正的数据执行,不会真实操作数据库,被称为惰性。(2)缓存使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数。

QuerySet 的 API 方法

  • all() :返回模型的所有对象

  • filter()(**kwargs) 用于返回符合条件的所有数据

  • get() 方法与 filter() 的作用类似,用于返回符合条件的单个对象但是可能会返回多个值

  • delete() :可以删除符合条件的所有对象

  • update() :将符合条件的所有对象的某个字段值进行更新

  • create()save() 方法的快捷方式,用于创建并保存一个新的对象

  • count() :返回符合条件的对象数量

  • order_by() :对返回的对象进行排序,默认为升序。降序则在字段名前面加负号

  • values():用来指定提取的数据中需要提取哪些字段

调用方法是:模型名.objects.方法名

比如views.py中的代码示例

queryset = GoodsCategory.objects.all()

category, created = GoodsCategory.objects.get_or_create(name=category_name)

goods = Goods.objects.filter(category=goods_category)

Instance

Instance指的是一个 Django 模型的单个实例,也就是数据库中的一行数据。相比于 QuerySet(查询集合),它是针对单个对象的操作,用于创建、更新或者删除单个模型实例。

QuerySet 适用于需要查找多个对象或进行聚合操作的场景,而 Instance 适用于单独对象的创建、修改和删除操作。

创建一个对象

Obj = Model(attr1=val1, attr2=val2),Obj.save()

更新一个对象

Obj = Model.objects.get(id=xxx),Obj.attr1 = val1,Obj.save()

删除一个对象

Obj = Model.objects.get(id=xxx),Obj.delete()

操作演示

打开shell

我们使用 shell 来熟悉 QuerySet 和 Instance 的操作

ctrl + `

打开 vscode 终端,执行进入 erp 目录,打开 shell

python manage.py shell
(ybw) PS D:\星球项目\django后端开发> cd .\erp\
(ybw) PS D:\星球项目\django后端开发\erp> python .\manage.py shell
(ybw) PS D:\星球项目\django后端开发\erp> python .\manage.py shell
Python 3.11.2 | packaged by Anaconda, Inc. | (main, Mar 27 2023, 23:35:04) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.13.2 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

导入 models.py 中的2个类

 from apps.models import *

models.py 中有2个类

GoodsCategory 和 Goods

## 产品分类表
class GoodsCategory(Model):
    """产品分类"""

    name = CharField(max_length=64, verbose_name='分类名称')
    remark = CharField(max_length=64, null=True, verbose_name='备注', blank=True)

## 产品表
class Goods(Model):
    """产品"""

    # 外键
    category = ForeignKey(GoodsCategory, on_delete=SET_NULL, related_name='goods_set', null=True, verbose_name='产品分类',
                          blank=True, )
    # on_delete 

    number = CharField(max_length=32, verbose_name='产品编号')
    name = CharField(max_length=64, verbose_name='产品名称')
    barcode = CharField(max_length=32, null=True, blank=True, verbose_name='条码')
    spec = CharField(max_length=64, null=True, blank=True, verbose_name='规格')
    shelf_life_days = IntegerField(null=True, verbose_name='保质期天数')
    purchase_price = FloatField(default=0, verbose_name='采购价')
    retail_price = FloatField(default=0, verbose_name='零售价')
    remark = CharField(max_length=128, null=True, blank=True, verbose_name='备注')

QuerySet 和 Instance 演示

QuerySet 示例

all() :返回全部对象

In [2]: GoodsCategory.objects.all()
Out[2]: <QuerySet [<GoodsCategory: 水果>, <GoodsCategory: 动物>, <GoodsCategory: 电脑>, <GoodsCategory: 眼镜>, <GoodsCategory: 衣服>, <GoodsCategory: 皮鞋>, <GoodsCategory: 茶壶>]>

In [6]: Goods.objects.all()
Out[6]: <QuerySet [<Goods: 苹果>, <Goods: 桃子>, <Goods: 猴子>, <Goods: 大象>]>

这里分别显示了GoodsCategoryGoods的全部对象

values():显示更详细信息

In [4]: GoodsCategory.objects.values()
Out[4]: <QuerySet [{'id': 2, 'name': '水果', 'remark': '水果'}, {'id': 3, 'name': '动物', 'remark': '动物'}, {'id': 9, 'name': '电脑', 'remark': None}, {'id': 13, 'name': '眼镜', 'remark': None}, {'id': 14, 'name': '衣服', 'remark': '衣服'}, {'id': 15, 'name': '皮鞋', 'remark': '皮鞋'}, {'id': 16, 'name': '茶壶', 'remark': None}]>

In [7]: Goods.objects.values()
Out[7]: <QuerySet [{'id': 1, 'category_id': 2, 'number': '1', 'name': '苹果', 'barcode': None, 'spec': None, 'shelf_life_days': 10, 'purchase_price': 3.0, 'retail_price': 5.0, 'remark': None}, {'id': 2, 'category_id': 2, 'number': '2', 'name': '桃子', 'barcode': None, 'spec': None, 'shelf_life_days': 10, 'purchase_price': 4.0, 'retail_price': 6.0, 'remark': None}, {'id': 3, 'category_id': 3, 'number': '3', 'name': '猴子', 'barcode': None, 'spec': None, 'shelf_life_days': 40, 'purchase_price': 60.0, 'retail_price': 100.0, 'remark': None}, {'id': 4, 'category_id': 3, 'number': '4', 'name': '大象', 'barcode': None, 'spec': None, 'shelf_life_days': 200, 'purchase_price': 100.0, 'retail_price': 200.0, 'remark': None}]>

可以看出GoodsCategory包含idnameremark 3个特征

Goods包含idcategory_idnumbernamebarcodespecshelf_life_dayspurchase_priceretail_priceremark 10个特征

In [16]: Goods.objects.values('number', 'name', 'retail_price')
Out[16]: <QuerySet [{'number': '1', 'name': '苹果', 'retail_price': 5.0}, {'number': '2', 'name': '桃子', 'retail_price': 6.0}, {'number': '3', 'name': '猴子', 'retail_price': 100.0}, {'number': '4', 'name': '大象', 'retail_price': 200.0}]>

只显示numbernameretail_price 3个特征

count():计算对象数目

In [19]: GoodsCategory.objects.all().count()
Out[19]: 7
In [20]: Goods.objects.values().count()
Out[20]: 4
In [32]: queryset = GoodsCategory.objects.all()
In [33]: queryset.count()
Out[33]: 7

可以看出GoodsCategory包含7个对象,Goods包含4个对象

同时QuerySet的结果可以赋给变量,进行后续操作

filter():筛选符合条件的对象

In [5]: GoodsCategory.objects.values().filter(remark=None)
Out[5]: <QuerySet [{'id': 9, 'name': '电脑', 'remark': None}, {'id': 13, 'name': '眼镜', 'remark': None}, {'id': 16, 'name': '茶壶', 'remark': None}]> 

返回remark=None的对象

In [18]: Goods.objects.values('number', 'name', 'retail_price').filter(number__gt=2)
Out[18]: <QuerySet [{'number': '3', 'name': '猴子', 'retail_price': 100.0}, {'number': '4', 'name': '大象', 'retail_price': 200.0}]>

返回number > 2的对象

In [23]: Goods.objects.values('number', 'name', 'retail_price').filter(number__gt=1, retail_price__lt=150)
Out[23]: <QuerySet [{'number': '2', 'name': '桃子', 'retail_price': 6.0}, {'number': '3', 'name': '猴子', 'retail_price': 100.0}]>

返回 number > 1 以及 retail_price < 150 的对象,即 filter 可以多个条件联合使用

exclude():排除符合条件的对象

In [21]: GoodsCategory.objects.values().exclude(remark=None)
Out[21]: <QuerySet [{'id': 2, 'name': '水果', 'remark': '水果'}, {'id': 3, 'name': '动物', 'remark': '动物'}, {'id': 14, 'name': '衣服', 'remark': '衣服'}, {'id': 15, 'name': '皮鞋', 'remark': '皮鞋'}]>

去除remark=None的对象,即筛选出remark != None的对象

update():修改数据并保存

In [25]: GoodsCategory.objects.filter(id=13).update(remark='眼镜')
Out[25]: 1
In [27]: GoodsCategory.objects.values().filter(id=13)
Out[27]: <QuerySet [{'id': 13, 'name': '眼镜', 'remark': '眼镜'}]>

GoodsCategoryid=13的对象的 remark 改成眼镜

delete():删除对象

In [28]: GoodsCategory.objects.filter(name='动物').delete()
Out[28]: (1, {'apps.GoodsCategory': 1})
In [29]: GoodsCategory.objects.all()
Out[29]: <QuerySet [<GoodsCategory: 水果>, <GoodsCategory: 电脑>, <GoodsCategory: 眼镜>, <GoodsCategory: 衣服>, <GoodsCategory: 皮鞋>, <GoodsCategory: 茶壶>]>

删除name="动物"的对象

order_by():对筛选结果排序

In [30]: Goods.objects.values('number', 'name', 'retail_price').order_by('retail_price')
Out[30]: <QuerySet [{'number': '1', 'name': '苹果', 'retail_price': 5.0}, {'number': '2', 'name': '桃子', 'retail_price': 6.0}, {'number': '3', 'name': '猴子', 'retail_price': 100.0}, {'number': '4', 'name': '大象', 'retail_price': 200.0}]>

将Goods的numbernameretail_price 3个特征 按照retail_price进行升序排列

In [31]: Goods.objects.values('number', 'name', 'retail_price').order_by('-retail_price')
Out[31]: <QuerySet [{'number': '4', 'name': '大象', 'retail_price': 200.0}, {'number': '3', 'name': '猴子', 'retail_price': 100.0}, {'number': '2', 'name': '桃子', 'retail_price': 6.0}, {'number': '1', 'name': '苹果', 'retail_price': 5.0}]>

通过添加负号,将 Goods 按照降序排列

Instance示例

get():指定一个对象

In [42]: Goods.objects.get(name='苹果')
Out[42]: <Goods: 苹果>
In [43]: Goods.objects.values().get(name='苹果')
Out[43]:
{'id': 1,
 'category_id': 2,
 'number': '1',
 'name': '苹果',
 'barcode': None,
 'spec': None,
 'shelf_life_days': 10,
 'purchase_price': 3.0,
 'retail_price': 5.0,
 'remark': None}

返回name="苹果"的对象

修改一个对象

In [44]: obj = Goods.objects.get(name='苹果')
In [45]: obj.purchase_price = 4.0
In [46]: obj.retail_price = 6.0
In [47]: obj.remark = '水果'
In [48]: obj.save()
In [52]: Goods.objects.values().get(name='苹果')
Out[52]:
{'id': 1,
 'category_id': 2,
 'number': '1',
 'name': '苹果',
 'barcode': None,
 'spec': None,
 'shelf_life_days': 10,
 'purchase_price': 4.0,
 'retail_price': 6.0,
 'remark': '水果'}

delete():删除一个对象

In [56]: GoodsCategory.objects.values()
Out[56]: <QuerySet [{'id': 2, 'name': '水果', 'remark': '水果'}, {'id': 9, 'name': '电脑', 'remark': None}, {'id': 13, 'name': '眼镜', 'remark': '眼镜'}, {'id': 14, 'name': '衣服', 'remark': '衣服'}, {'id': 15, 'name': '皮鞋', 'remark': '皮鞋'}, {'id': 16, 'name': '茶壶', 'remark': None}]>
In [58]: obj2 = GoodsCategory.objects.get(id=16)
In [59]: obj2
Out[59]: <GoodsCategory: 茶壶>
In [60]: obj2.delete()
Out[60]: (1, {'apps.GoodsCategory': 1})
In [61]: GoodsCategory.objects.values()
Out[61]: <QuerySet [{'id': 2, 'name': '水果', 'remark': '水果'}, {'id': 9, 'name': '电脑', 'remark': None}, {'id': 13, 'name': '眼镜', 'remark': '眼镜'}, {'id': 14, 'name': '衣服', 'remark': '衣服'}, {'id': 15, 'name': '皮鞋', 'remark': '皮鞋'}]>

删除GoodsCategoryid=2的对象,即name="茶壶"的对象

最后更新于