78.objects对象所属类原理分析

时间:2024-06-09 17:03:32
def index3(request):
# 查找文章题目中包含中国的文章分类
category = Category.objects.filter(article__title__contains='中国')
print(type(Category.objects))
print(type(category))
# print(category.query)
return HttpResponse("success!")
返回的结果为:

<class 'django.db.models.manager.Manager'>

<class 'django.db.models.query.QuerySet'>

1. 由打印的结果我们可以看出,type(Category.objects)的类型为Manager。因此,我们可以将鼠标放在objects上按ctrl+b(或者是从from django.db.models.manager import Manager,将鼠标放在Manager上按ctrl+b),进入Manager类。

class Manager(BaseManager.from_queryset(QuerySet)):
pass
2.进入之后我们会发现其实Manager类为一个空的类,并没有定义的方法或是属性。但是它继承了父类BaseManager的类方法from_queryset(),from_queryset()中传递了一个QuerySet类名。
3. 接着我们将鼠标放在from_queryset()方法上,ctrl+b,查看from_queryset()方法是怎么实现的?
# 在这里没有写明BaseManager是继承了哪个类,默认情况下就是继承了objects。即为class BaseManager(objects):
class BaseManager:
@classmethod
# 传进来的参数cls代表的是当前的类名BaseManager,
# queryset_class:代表的是from_queryset()接收的值QuerySet,而class_name为默认值None
def from_queryset(cls, queryset_class, class_name=None):
# 因为我们的from_queryset()方法只接受一个参数,所以class_name为None,满足if条件
if class_name is None:
# class_name=BaseManagerFromQuerySet
class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
# type()函数可以用来动态创建类:返回type(创建的类名:BaseManagerFromQuerySet,继承的类:可以是单继承也可以是多继承,用元组表示:(cls,), class_dict)
# class_dict:{
# '_queryset_class': QuerySet,
# **cls._get_queryset_methods(QuerySet):代表的是调用当前类BaseManager的_get_queryset_methods()方法所得到的返回值。同样我们可以将鼠标放在_get_queryset_methods()方法上,ctrl+b查看方法的返回值。
}
return type(class_name, (cls,), {
'_queryset_class': queryset_class,
**cls._get_queryset_methods(queryset_class),
})
4. **cls._get_queryset_methods(queryset_class)相关说明:
class BaseManager:
@classmethod
def _get_queryset_methods(cls, queryset_class):
# create_method()方法中传递两个参数name和method,返回的是manager_method,
def create_method(name, method):
def manager_method(self, *args, **kwargs):
return getattr(self.get_queryset(), name)(*args, **kwargs)
manager_method.__name__ = method.__name__
manager_method.__doc__ = method.__doc__
return manager_method
# 定义一个新的方法字典
new_methods = {}
# 遍历QuerySet的函数,找到name和method
for name, method in inspect.getmembers(queryset_class, predicate=inspect.isfunction):
# Only copy missing methods.
# hasattr(cls,name)返回的对象是否具有给定名称的属性,如果返回值为True就继续以下操作
if hasattr(cls, name):
continue
# 拷贝公共的方法或者是属性queryset_only=False的方法。
# Only copy public methods or methods with the attribute `queryset_only=False`.
queryset_only = getattr(method, 'queryset_only', None)
if queryset_only or (queryset_only is None and name.startswith('_')):
continue
# Copy the method onto the manager.
# 在这里我们可以将鼠标放在create_method()方法上,ctrl+b,查看该方法执行的操作:返回了一个manager_method(manager方法名)被赋值给new_methods
new_methods[name] = create_method(name, method)
# 将拷贝的多个函数都返回给new_methods,并且返回new_methods.
# 此时的_get_queryset_methods(QuerySet)的返回值就是拷贝的多个QuerySet的方法。
return new_methods
5. 因此,我们的from_queryset()方法返回的return type(class_name, (cls,), { '_queryset_class': queryset_class, **cls._get_queryset_methods(queryset_class),})中 **cls._get_queryset_methods(queryset_class)的值为:
	# class_dict:{
# '_queryset_class': QuerySet,
# **cls._get_queryset_methods(QuerySet):得到拷贝的QuerySet的多个方法
# }
6. 因此我们from_queryset(QuerySet)就拷贝到了QuerySet的多个方法,而我们的空类Manager因为继承了BaseManager.from_queryset(QuerySet)也就有了QuerySet很多的方法。所以我们可以在模型名.objects上就可以调用很多QuerySet的方法。
class Manager(BaseManager.from_queryset(QuerySet)):
pass