- objects
对于Django中的每一个模型,django都会添加一个objects属性,这个属性就是一个管理这个模型的Manager对象。
比如:我们创建一个模型Book
打印Book的objects属性,并打印其类型
结果:
可以明显的看到objects是Book模型的一个属性,是Django的Manager模型管理器的一个对象。
- 我们定义模型的时候并没有定义这个属性,这个属性什么时候创建的呢?
是在定义模型的时候由Django为我们创建的。在定义模型的时候必须继承models.Model类,只有继承了这个类之后,该类才能算是Django模型。看看Model类
它由继承自由meta class(元类)ModelBase创建出来的类。那看看ModelBase
可以看到ModelBase是所有model的metaclass。在ModelBase的__new__方法(用于创建该类对象)最后有这个方法调用:
那看看这个方法:
这个类为创建ModelBase实例做出了预前操作,在这个方法的最后:
为这个ModelBase实例添加了objects属性,这个属性就是一个Manager对象。
总结:objects是由metaclass(元类)BaseModel创建的,所有由BaseModel创建的类都包括objects属性,它是一个Manager对象(模型管理器)。Model继承自由BaseModel创建的对象,而我们创建的模型都继承自Model,所以我们创建的模型都包括了objects属性,也就是每个模型的管理器Manager。
- Manager
我们按住Ctrl键左键点击进入objects时,都会直接跳转到Manager。因为它是由元类BaseModel创建的属性,并不是直接声明的类属性,所以会直接跳转到Manager.
可以看到Manager继承自BaseManager的from_queryset(QuerySet)所创建的类对象。看看这个方法
cls :BaseManager类对象
queryset_class:QuerySet类对象
class_name:要创建的类的名字
可以看到这个方法返回了一个继承自BaseManager的类对象。在返回之前更新了类字典(新创建类的成员,成员由QuerySet类对象而来。)
接着看看_get_queryset_methods()
是一个多层嵌套函数,在最底层的函数调用了get_queryset()方法。
接着它将QuerySet中所有的可以被外部使用,并且在BaseManager中没有被定义的方法拷贝(更新)到类字典中。所以我们由BaseManager创建的 所有类都有了QuerySet类中的所有公开方法。这些方法就是我们管理器可以调用的方法(比如filter()、arrgerate()、get()、last()、first()……)。objects是一个Manager对象,Manager继承自BaseManager,所以objects都可以调用这些方法。
再回去看get_queryset()方法
可以看到它它返回了一个QuerySet对象。
QuerySet表示一组对象的延迟数据库查找。
最重要的是子类覆盖掉此方法可以很轻松的完成自定义管理器Manager的功能。这个时候我们就可以写自定义管理器了。
总结:Manager为我们创建model的管理器,它里面包括了我们模型可以通过管理器所有可以操作的方法,我们可以自定义管理器并重写get_queryset()方法来自定义我们的管理器。(可以认为管理器就是一个QuerySet的派生类)
- 自定义管理器
objects是由ModelBase为我们创建的每一个model的属性,这个属性做为我们的model的管理器来使用。
通过覆盖管理器Manager中的get_queryset()方法可以自定义我们的管理器。如下:
第一步:为我们的model指定管理器对象(模型的属性)
第二部:创建我们的管理器 (一个Manager类对象),继承自models.Manager.
第三部:覆盖get_queryset()方法,实现自定定义管理器。
这是时候我们的自定义管理器就创建好了。
以前我们使用的是objects管理器,当指定了管理器之后,ojects将失效。以后使用管理器就是manager了。
这个取缔过程是由Django做的。通过迁移文件,完成模型和数据库的ORM(Object Relational Mapping,对象关系映射),并对该模型进行管理设置:
可以看到迁移文件中指定了完成ORM的属性以及我们自定义的信息。
- 使用场景
生产环境中,数据是非常重要的,删除数据经常的是逻辑删除(设置是否删除字段),而不是物理删除。而我们使用自带的管理器objects查询到的结果集通常是整张表的数据,而这不是我们想要的。而我们想要的是没有进行逻辑删除的数据,所以可以自定义管理器,实现对管理器结果的初步过滤,这样就避免了我们在使用objects默认管理器时额外的操作(每次进行数据过滤都需要先过滤没有逻辑删除的数据)。在管理器中我们也可以重写其他方法完成自定义的功能。
实际上可以认为管理器就是操作mysql的一个cursor(游标对象),而我们通过管理器调用的一些列方法相当于通过游标对象执行的sql语句。