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'>python

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
相关文章
相关标签/搜索