最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Django ORM 查詢管理器源碼解析

 更新時(shí)間:2019年08月05日 10:57:23   作者:搗亂小子  
這篇文章主要介紹了Django ORM 查詢管理器源碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

ORM 查詢管理器

對(duì)于 ORM 定義: 對(duì)象關(guān)系映射, Object Relational Mapping, ORM, 是一種程序設(shè)計(jì)技術(shù),用于實(shí)現(xiàn)面向?qū)ο缶幊陶Z(yǔ)言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換。從效果上說(shuō),它其實(shí)是創(chuàng)建了一個(gè)可在編程語(yǔ)言里使用的“虛擬對(duì)象數(shù)據(jù)庫(kù)”。ORM 能大大簡(jiǎn)化并抽象數(shù)據(jù)庫(kù)的操作.

假設(shè) django 的一個(gè)工程中包含一個(gè)名為 Book 的模塊(model), 在 views.py 的函數(shù)中可能會(huì)寫(xiě)出查詢語(yǔ)句:

# views.py
def index(request):
  book_set = Book.objects.filter(id=1)
  或者
  book_set = Book.objects.all()
  ......

ORM 的作用就是這樣, 并不需要寫(xiě)更復(fù)雜的 SQL 語(yǔ)句, 所有的的事情都被 ORM 代勞了.

上面中, Book 實(shí)際上是一個(gè) Model 實(shí)例, 但先是從 Book.objects 開(kāi)始說(shuō)起. Book.objects 實(shí)際上是一個(gè) Manager 類實(shí)例, 每個(gè) Model 都會(huì)有一個(gè), 用戶的查詢操作幾乎是從這里開(kāi)始的. 萬(wàn)萬(wàn)可以將 Model 實(shí)例理解為關(guān)系表中的一個(gè)表項(xiàng)數(shù)據(jù), 而 Manager 實(shí)例可以理解數(shù)據(jù)庫(kù)查詢的入口.

實(shí)際上, 無(wú)論如何都在 Model 類的源碼中找到任何 objects 屬性的字眼, 因此它肯定是在某個(gè)時(shí)間點(diǎn)上增加的. 可以在 django.db.models.manager.py 中找到下面的函數(shù):

這個(gè)函數(shù)確保每一個(gè) model 都有一個(gè)管理器 objects

def ensure_default_manager(sender, **kwargs):
  ......
  if not getattr(cls, '_default_manager', None):
    # Create the default manager, if needed.
    try:
      cls._meta.get_field('objects')
      raise ValueError("Model %s must specify a custom Manager, because it has a field named 'objects'" % cls.__name__)
    except FieldDoesNotExist:
      pass
    """
    關(guān)鍵的一步, 將一個(gè) Manager 實(shí)例掛鉤到 cls.objects, 將 model.add_to_class() 方法羅列如下;
    def add_to_class(cls, name, value):
      if hasattr(value, 'contribute_to_class'):
        value.contribute_to_class(cls, name)
      else:
        setattr(cls, name, value)
    關(guān)鍵是 Manager 有 contribute_to_class() 方法, 由此看來(lái), model.objects 并不是一個(gè) Manager 實(shí)例, 實(shí)際上他是一個(gè) ManagerDescriptor 實(shí)例.
    """
    cls.add_to_class('objects', Manager())
    cls._base_manager = cls.objects
  elif not getattr(cls, '_base_manager', None):
    default_mgr = cls._default_manager.__class__
    if (default_mgr is Manager or
        getattr(default_mgr, "use_for_related_fields", False)):
      cls._base_manager = cls._default_manager
    else:
      # Default manager isn't a plain Manager class, or a suitable
      # replacement, so we walk up the base class hierarchy until we hit
      # something appropriate.
      for base_class in default_mgr.mro()[1:]:
        if (base_class is Manager or
            getattr(base_class, "use_for_related_fields", False)):
          cls.add_to_class('_base_manager', base_class())
          return

由此可以發(fā)現(xiàn), Model.objects 在這個(gè)時(shí)候被添加了. 因此用戶可以在代碼中使用 Book.objects. 至于這個(gè)函數(shù)在何時(shí)被調(diào)用, 待后面會(huì)詳述 django 內(nèi)部的信號(hào)機(jī)制. 暫且你可以將其理解為在 django 服務(wù)器啟動(dòng)的時(shí)候, 這些會(huì)被自動(dòng)調(diào)用就好了.

Manager 實(shí)現(xiàn)

Manager 保護(hù)技法

如果可以在 book_set = Book.objects.filter(id=1) 這一句上設(shè)置斷點(diǎn), 并 step into 的時(shí)候, 發(fā)現(xiàn) Book.objects 實(shí)際上的實(shí)際上不是一個(gè) Manager 實(shí)例, 而是一個(gè) ManagerDescriptor 實(shí)例, 這是 django 特意為 Manager 做的一層包裝. 為什么要這么做 ?

django 規(guī)定, 只有 Model 類可以使用 objects, Model 類實(shí)例不可以. 請(qǐng)注意區(qū)分類和類實(shí)例之間的區(qū)別.

我認(rèn)為這樣做是有道理的. Book.objects.filter(id=1) 返回的是 QuerySet 對(duì)象, 而 QuerySet 對(duì)象可以看成是 Model 實(shí)例的集合, 也就是 book_set 是 Model 實(shí)例的集合. 假使 「Model 類的實(shí)例可以使用 objects 屬性」, 即「從一本書(shū)中查詢書(shū)」這在語(yǔ)意上不通過(guò). 只能是「從書(shū)的集合(Book)中查詢書(shū)」.

所以 django 用 ManagerDescriptor 特意為 Manager 做的一層包裝. 可以在 django.db.models.manager.py 中找到

ManagerDescriptor 的實(shí)現(xiàn):

class ManagerDescriptor(object):
  """

很經(jīng)典的掩飾, 為 Manager 特殊設(shè)定 Descriptor, 從而, 只能讓類訪問(wèn), 而不能讓類的實(shí)例來(lái)訪問(wèn). 具體是靠 __get__(self, instance, type=None) 方法來(lái)實(shí)現(xiàn)來(lái)的: 第二個(gè)參數(shù) instance, 當(dāng) class.attr 的時(shí)候, instance 為 None; 當(dāng) obj.attr 的時(shí)候, instance 為 obj.

  """
  # This class ensures managers aren't accessible via model instances.
  # For example, Poll.objects works, but poll_obj.objects raises AttributeError.

  def __init__(self, manager):
    self.manager = manager
  def __get__(self, instance, type=None):
    if instance != None:
      raise AttributeError("Manager isn't accessible via %s instances" % type.__name__)
    return self.manager

所要詳述的是 __get__() 函數(shù). python 的語(yǔ)法里有修飾器(descriptor)這么一說(shuō), 而 python 的屬性類型就是這么實(shí)現(xiàn)的. descriptor 實(shí)現(xiàn) __get__(), __set__(), 接著將其添加到一個(gè)類中. 譬如下面的例子:

class Celsius(object):
  def __init__(self, value=0.0):
    self.value = float(value)
  def __get__(self, instance, owner):
    print instance,owner
    return self.value
  def __set__(self, instance, value):
    print instance,value
    self.value = float(value)

class Temperature(object):
  celsius = Celsius()

t = Temperature()
t.celsius
Temperature.celsius

當(dāng)對(duì) descriptor 賦值的時(shí)候, 其本身 __set__ 會(huì)被調(diào)用, 取值的時(shí)候 __get__() 會(huì)被調(diào)用. __set__,__get__ 函數(shù)的 instance 參數(shù)即為類實(shí)例(所以, t.cellsius 調(diào)用 __get__() 的時(shí)候, instance 參數(shù)是 t, Temperature.celsius 調(diào)用 __get__() 的時(shí)候, instance 參數(shù)是 Temperature).

所以, 可以通過(guò)判斷 instance 來(lái)判斷調(diào)用者是否是類實(shí)例. 也就由此可以拒絕類實(shí)例的訪問(wèn), 發(fā)現(xiàn) ManagerDescriptor 就是這么實(shí)現(xiàn)的.

總結(jié)

Book.objects 實(shí)際上是一個(gè) Manager, 實(shí)際上的實(shí)際上卻是一個(gè) ManagerDescriptor, 但真正起作用的還是 Manager, ManagerDescriptor 是修飾器, 是 django 的保護(hù)技法.

從 Manager 的實(shí)現(xiàn)來(lái)看, 它的多數(shù)函數(shù)會(huì)返回 QuerySet 對(duì)象, 而且透漏了一個(gè)重點(diǎn): QuerySet 對(duì)象可以看成是 Model 實(shí)例的集合.

我已經(jīng)在 github 備份了 Django 源碼的注釋: Decode-Django, 有興趣的童鞋 fork 吧.

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python MySQLdb Linux下安裝筆記

    Python MySQLdb Linux下安裝筆記

    這篇文章主要介紹了Python MySQLdb Linux下安裝筆記,本文分別講解了快速安裝和手動(dòng)編譯安裝兩種方法,并分別講解了操作步驟,需要的朋友可以參考下
    2015-05-05
  • Python實(shí)現(xiàn)繪制多種激活函數(shù)曲線詳解

    Python實(shí)現(xiàn)繪制多種激活函數(shù)曲線詳解

    所謂激活函數(shù)(Activation?Function),就是在人工神經(jīng)網(wǎng)絡(luò)的神經(jīng)元上運(yùn)行的函數(shù),負(fù)責(zé)將神經(jīng)元的輸入映射到輸出端。這篇文章主要介紹了Python如何實(shí)現(xiàn)繪制多種激活函數(shù)曲線,希望對(duì)大家有所幫助
    2023-04-04
  • pytorch Dataset,DataLoader產(chǎn)生自定義的訓(xùn)練數(shù)據(jù)案例

    pytorch Dataset,DataLoader產(chǎn)生自定義的訓(xùn)練數(shù)據(jù)案例

    這篇文章主要介紹了pytorch Dataset, DataLoader產(chǎn)生自定義的訓(xùn)練數(shù)據(jù)案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-03-03
  • python字符串操作詳析

    python字符串操作詳析

    這篇文章主要介紹了python字符串操作,字符串是不可變類型可以重新賦值,但不可以索引改變其中一個(gè)值,只能拼接字符串建立新變量,下面來(lái)了解具體內(nèi)容吧,需要的小伙伴可以參考一下
    2022-02-02
  • 淺談Python對(duì)內(nèi)存的使用(深淺拷貝)

    淺談Python對(duì)內(nèi)存的使用(深淺拷貝)

    這篇文章主要介紹了淺談Python對(duì)內(nèi)存的使用(深淺拷貝),具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Python中如何檢查字符串是否包含列表中的元素

    Python中如何檢查字符串是否包含列表中的元素

    在數(shù)據(jù)預(yù)處理或糾錯(cuò)的過(guò)程中可能會(huì)用到對(duì)列表中是否含有我們需要的字符串的判斷,下面這篇文章主要給大家介紹了關(guān)于Python中如何檢查字符串是否包含列表中的元素的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • python數(shù)字圖像處理實(shí)現(xiàn)直方圖與均衡化

    python數(shù)字圖像處理實(shí)現(xiàn)直方圖與均衡化

    在圖像處理中,直方圖是非常重要,也是非常有用的一個(gè)處理要素。這篇文章主要介紹了python數(shù)字圖像處理實(shí)現(xiàn)直方圖與均衡化,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 利用 PyCharm 實(shí)現(xiàn)本地代碼和遠(yuǎn)端的實(shí)時(shí)同步功能

    利用 PyCharm 實(shí)現(xiàn)本地代碼和遠(yuǎn)端的實(shí)時(shí)同步功能

    這篇文章主要介紹了利用 PyCharm 實(shí)現(xiàn)本地代碼和遠(yuǎn)端的實(shí)時(shí)同步功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 淺談tf.train.Saver()與tf.train.import_meta_graph的要點(diǎn)

    淺談tf.train.Saver()與tf.train.import_meta_graph的要點(diǎn)

    這篇文章主要介紹了淺談tf.train.Saver() 與tf.train.import_meta_graph的要點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • python2 與python3的print區(qū)別小結(jié)

    python2 與python3的print區(qū)別小結(jié)

    這篇文章主要介紹了python2 與python3的print區(qū)別小結(jié),需要的朋友可以參考下
    2018-01-01

最新評(píng)論

渭南市| 富蕴县| 大化| 祁阳县| 陈巴尔虎旗| 昌黎县| 曲松县| 枞阳县| 龙岩市| 海林市| 普陀区| 滦南县| 孝感市| 夏河县| 汨罗市| 南溪县| 临沧市| 平顶山市| 南昌县| 怀来县| 和顺县| 江门市| 仙游县| 平潭县| 伊通| 林口县| 轮台县| 英山县| 广水市| 平乡县| 施秉县| 大邑县| 河北区| 绥滨县| 黎川县| 关岭| 安新县| 梨树县| 广河县| 镶黄旗| 正阳县|