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

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
posted @ 2020-02-05 21:20  一笑而过~一笑奈何  阅读(164)  评论(0编辑  收藏  举报