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属性值,因为描述符作为属性访问时是自动调用的
且对于类属性和类的实例属性,有着不同的调用规则
- 描述符对象作为类属性时候,class.x 将被转化为
1
|
class.__dict__['x'].__get__(None, class)
|
- 描述符对象作为实例属性: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在使用实例对象访问属性时,会按照不同的优先级依次在类定义中查找,最终找到了实例属性并返回