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

最新文章

  1. 经典排序算法 – 插入排序Insertion sort
  2. NDK开发-简介&amp;环境搭建(Eclipse,Android Studio)
  3. Mongodb Manual阅读笔记:CH9 Sharding
  4. nsstring打印结构体
  5. 大文件遍历shell脚本
  6. php设计模式之单例模式
  7. Centos6 下启动httpd报错 Could not reliably determine the server&#39;s解决方法
  8. Android WifiDirect学习(一)
  9. (转)函数中使用 ajax 异步 同步 返回值错误 主函数显示返回值总是undefined -- ajax使用总结
  10. select自动选中
  11. Cocos2dx游戏开发系列笔记13:一个横版拳击游戏Demo完结篇
  12. [帖子收集]通用Windows平台(UWP)
  13. Ubuntu 12.04 怎样安装 Google Chrome
  14. 关于C#的学习心得体会
  15. NC二次开发常用的表
  16. Android程序崩溃异常收集框架
  17. 我认知的javascript之函数调用
  18. Servlet 文件上传
  19. 能添加图标的label
  20. UVa 1149 装箱

热门文章

  1. 10. Regular Expression Matching正则表达式匹配
  2. 值得一学的C语言
  3. MyBatis Generator 下划线转驼峰命名
  4. 解决使用xampp无法通过ip访问的问题
  5. HDU - 1166 敌兵布阵 (线段树---点修改)
  6. POJ 1151:Atlantis 线段树+扫描线
  7. 13.56mhz自动寻卡功能业界最低功耗:SI522
  8. windows中git输错密码后不能修改问题
  9. [题解] LuoguP6071 [MdOI2020] Treequery
  10. NASA的10条编码规则