zoukankan      html  css  js  c++  java
  • 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
    
    始于才华,忠于颜值;每件事情在成功之前,看起来都是天方夜谭。一无所有,就是无所不能。
  • 相关阅读:
    Android核心分析之十七电话系统之rilD
    Android核心分析之十六Android电话系统-概述篇
    Android核心分析之十五Android输入系统之输入路径详解
    Android核心分析之十四Android GWES之输入系统
    Android 核心分析之十三Android GWES之Android窗口管理
    Android 核心分析之十二Android GEWS窗口管理之基本架构原理
    Android核心分析 之十一Android GWES之消息系统
    Android核心分析 之十Android GWES之基本原理篇
    Android核心分析 之九Zygote Service
    Android 核心分析 之八Android 启动过程详解
  • 原文地址:https://www.cnblogs.com/guyan-2020/p/12266666.html
Copyright © 2011-2022 走看看