Django 的 orm 中使用到了元類和描述符這些高級(jí)知識(shí)肚吏,了解一下的可以看看這篇文章。
元類其實(shí)就是用來定義類的,我的理解是這樣的:當(dāng)很多類有相同的屬性,那么就可以提取這些相同的屬性到一個(gè)類中笼蛛,元類就是用來封裝那些的,或者給某些類添加一些屬性蛉鹿,定制類滨砍。你看看 Django model
寫的代碼有多少,而背后元類默默做了很多東西妖异。
Django model
需要繼承自 models.Model
惋戏,跟蹤進(jìn)去發(fā)現(xiàn) class Model(metaclass=ModelBase):
,Model
其實(shí)是根據(jù) ModelBase
構(gòu)建的他膳,在實(shí)例化的時(shí)候响逢,會(huì)首先執(zhí)行 ModelBase
的 __new__
方法。里面為我們封裝了 _meta
這么一個(gè)屬性矩乐,具體的可以看看源碼龄句。
我們查詢數(shù)據(jù)的時(shí)候一直用到 obejcts
方法回论,那么它是哪來的呢散罕?在封裝self._meta
后調(diào)用了 _prepare
分歇,在它里面發(fā)現(xiàn)了一個(gè)管理器 manager
。
if not opts.managers:
if any(f.name == 'objects' for f in opts.fields):
raise ValueError(
"Model %s must specify a custom Manager, because it has a "
"field named 'objects'." % cls.__name__
)
manager = Manager()
manager.auto_created = True
cls.add_to_class('objects', manager)
這里使用了 manager
欧漱,然后注冊了 objects
职抡。那么來看看 Manager
:
class Manager(BaseManager.from_queryset(QuerySet)):
pass
什么也沒做,只是根據(jù) BaseManager
的類方法構(gòu)造了一個(gè)類误甚,然后繼承了它缚甩,就是 QuerySet
,到這里窑邦,你就大體明白了吧擅威,我們一般查詢出來的都是一個(gè) QuerySet
對象。
@classmethod
def from_queryset(cls, queryset_class, class_name=None):
if class_name is None:
class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
class_dict = {
'_queryset_class': queryset_class,
}
class_dict.update(cls._get_queryset_methods(queryset_class))
return type(class_name, (cls,), class_dict)
這里使用了 type
來創(chuàng)造一個(gè)類冈钦。
其實(shí)準(zhǔn)確來說郊丛,Manager
應(yīng)該是繼承了兩個(gè)類 BaseManager
和 QuertSet
。
再來看看 add_to_class
:
def add_to_class(cls, name, value):
# We should call the contribute_to_class method only if it's bound
if not inspect.isclass(value) and hasattr(value, 'contribute_to_class'):
value.contribute_to_class(cls, name)
else:
setattr(cls, name, value)
這里又調(diào)用了 manager
的 contribute_to_class
方法:
def contribute_to_class(self, model, name):
if not self.name:
self.name = name
self.model = model
setattr(model, name, ManagerDescriptor(self))
model._meta.add_manager(self)
又給 objects
賦值了一個(gè) ManagerDescriptor
實(shí)例瞧筛,這個(gè)是干嘛的呢厉熟?屬性描述符:
class ManagerDescriptor:
def __init__(self, manager):
self.manager = manager
def __get__(self, instance, cls=None):
if instance is not None:
raise AttributeError("Manager isn't accessible via %s instances" % cls.__name__)
if cls._meta.abstract:
raise AttributeError("Manager isn't available; %s is abstract" % (
cls._meta.object_name,
))
if cls._meta.swapped:
raise AttributeError(
"Manager isn't available; '%s.%s' has been swapped for '%s'" % (
cls._meta.app_label,
cls._meta.object_name,
cls._meta.swapped,
)
)
return cls._meta.managers_map[self.manager.name]
這里做了一些限制。
Django orm
四個(gè)重要類:
Model
较幌,QuerySet
揍瑟,Query
,Objects
乍炉。
QuerySet
主要是定義了一些接口绢片,如 filter
, count
等。它是惰性求值的岛琼,它并不直接求出值底循,只是在需要的時(shí)候查詢。
Query
實(shí)現(xiàn) sql
的拼接衷恭,它將語句交給 sql
編譯對象此叠。
一次查詢過程:
如果還想深入,可以看看
QuerySet
的源碼随珠。ps:
objects
是一個(gè) Manager
實(shí)例灭袁,而Manager
是一個(gè)空殼,它繼承自 QuerySet
窗看。