Django ORM原理

为什么创建的Model会自动拥有名称为id的主键

关键代码

查询管理器是什么?

它又是怎么添加到Model中的?

QuerySet是什么样的结构?

Python中的元类

1
2
3
4
5
6
7
class BBSMeta(type):
	"""
	使用元类给类添加描述信息
	"""
	def __new__(cls, name, bases, attrs):
		attrs['desc'] = lambda self: 'django bbs'
		return type.__new__(cls, name, bases, attrs)

Python的描述符

只要实现了get,set,delete中的任意一个方法,这个类对象就被称为描述符,且这个类对象的实例就有了一些特殊的特性

定义一个描述符对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Example(object):
	"""
	一个描述符的实例
	"""
	def __init__(self, name='django'):
		self.name = name
	def __get__(self, instance, owner):
		return self.name
	def __set__(self, instance, value):
		self.name = value

上面的实现了get和set方法,所以Example是一个描述符对象

当我们将描述符对象作为一个类的雷属性时候

1
2
3
4
class A(object):
	x = Example()
>>> A.x
'django'

可以看到A.x直接输出了name属性值,因为描述符作为属性访问时是自动调用的 且对于类属性和类的实例属性,有着不同的调用规则

  1. 描述符对象作为类属性时候,class.x 将被转化为
1
class.__dict__['x'].__get__(None, class)
  1. 描述符对象作为实例属性:object.x将被转化为
1
type(object).__diuct__['x'].__get__(object, type(object))

所以访问A.x 相当于访问

1
A.__dict__['x'].__get__(None, A)

而对于第二种规则

1
2
3
4
5
6
class B(object):
	def __init__(self):
		self.x = Example()
>>> b = B()
>>> b.x
<Example object at ox109c12f60>

从输出可以看到,访问实例属性并没有调用__get__方法,而是直接返回了这个描述示例对象, 这是因为根据调用规则

1
type(b).__dict__['x'] 是不存在的抛出KeyError错误),所以不会访问后面的get方法

之所以在访问b.x的时候没有出现错误,是因为Python在使用实例对象访问属性时,会按照不同的优先级依次在类定义中查找,最终找到了实例属性并返回