Django orm 再次學(xué)習(xí)

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è)類 BaseManagerQuertSet

再來看看 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)用了 managercontribute_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揍瑟,QueryObjects乍炉。
QuerySet 主要是定義了一些接口绢片,如 filter, count 等。它是惰性求值的岛琼,它并不直接求出值底循,只是在需要的時(shí)候查詢。
Query 實(shí)現(xiàn) sql 的拼接衷恭,它將語句交給 sql 編譯對象此叠。

一次查詢過程:

Django 模型查詢過程

如果還想深入,可以看看 QuerySet 的源碼随珠。
ps:objects 是一個(gè) Manager 實(shí)例灭袁,而
Manager 是一個(gè)空殼,它繼承自 QuerySet窗看。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茸歧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子显沈,更是在濱河造成了極大的恐慌软瞎,老刑警劉巖逢唤,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涤浇,居然都是意外死亡鳖藕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門只锭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來著恩,“玉大人,你說我怎么就攤上這事蜻展『硖埽” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵纵顾,是天一觀的道長伍茄。 經(jīng)常有香客問我,道長施逾,這世上最難降的妖魔是什么敷矫? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮音念,結(jié)果婚禮上沪饺,老公的妹妹穿的比我還像新娘。我一直安慰自己闷愤,他們只是感情好整葡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讥脐,像睡著了一般遭居。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旬渠,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天俱萍,我揣著相機(jī)與錄音,去河邊找鬼告丢。 笑死枪蘑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岖免。 我是一名探鬼主播岳颇,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颅湘!你這毒婦竟也來了话侧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對情侶失蹤闯参,失蹤者是張志新(化名)和其女友劉穎瞻鹏,沒想到半個(gè)月后悲立,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡新博,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年薪夕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叭披。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寥殖,死狀恐怖玩讳,靈堂內(nèi)的尸體忽然破棺而出涩蜘,到底是詐尸還是另有隱情,我是刑警寧澤熏纯,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布同诫,位于F島的核電站,受9級(jí)特大地震影響樟澜,放射性物質(zhì)發(fā)生泄漏误窖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一秩贰、第九天 我趴在偏房一處隱蔽的房頂上張望霹俺。 院中可真熱鬧,春花似錦毒费、人聲如沸丙唧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽想际。三九已至,卻和暖如春溪厘,著一層夾襖步出監(jiān)牢的瞬間胡本,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工畸悬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侧甫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓蹋宦,卻偏偏與公主長得像披粟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子妆档,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容