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
相關文章
相關標籤/搜索