亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Django ORM 查詢管理器源碼解析

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

ORM 查詢管理器

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

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

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

ORM 的作用就是這樣, 并不需要寫更復雜的 SQL 語句, 所有的的事情都被 ORM 代勞了.

上面中, Book 實際上是一個 Model 實例, 但先是從 Book.objects 開始說起. Book.objects 實際上是一個 Manager 類實例, 每個 Model 都會有一個, 用戶的查詢操作幾乎是從這里開始的. 萬萬可以將 Model 實例理解為關系表中的一個表項數(shù)據(jù), 而 Manager 實例可以理解數(shù)據(jù)庫查詢的入口.

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

這個函數(shù)確保每一個 model 都有一個管理器 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
    """
    關鍵的一步, 將一個 Manager 實例掛鉤到 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)
    關鍵是 Manager 有 contribute_to_class() 方法, 由此看來, model.objects 并不是一個 Manager 實例, 實際上他是一個 ManagerDescriptor 實例.
    """
    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 在這個時候被添加了. 因此用戶可以在代碼中使用 Book.objects. 至于這個函數(shù)在何時被調(diào)用, 待后面會詳述 django 內(nèi)部的信號機制. 暫且你可以將其理解為在 django 服務器啟動的時候, 這些會被自動調(diào)用就好了.

Manager 實現(xiàn)

Manager 保護技法

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

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

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

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

ManagerDescriptor 的實現(xiàn):

class ManagerDescriptor(object):
  """

很經(jīng)典的掩飾, 為 Manager 特殊設定 Descriptor, 從而, 只能讓類訪問, 而不能讓類的實例來訪問. 具體是靠 __get__(self, instance, type=None) 方法來實現(xiàn)來的: 第二個參數(shù) instance, 當 class.attr 的時候, instance 為 None; 當 obj.attr 的時候, 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 的語法里有修飾器(descriptor)這么一說, 而 python 的屬性類型就是這么實現(xiàn)的. descriptor 實現(xiàn) __get__(), __set__(), 接著將其添加到一個類中. 譬如下面的例子:

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

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

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

總結(jié)

Book.objects 實際上是一個 Manager, 實際上的實際上卻是一個 ManagerDescriptor, 但真正起作用的還是 Manager, ManagerDescriptor 是修飾器, 是 django 的保護技法.

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

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

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • numpy展平數(shù)組ndarray.flatten()詳解

    numpy展平數(shù)組ndarray.flatten()詳解

    這篇文章主要介紹了numpy展平數(shù)組ndarray.flatten()詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Python之日期與時間處理模塊(date和datetime)

    Python之日期與時間處理模塊(date和datetime)

    這篇文章主要介紹了Python之日期與時間處理模塊(date和datetime),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • Django實現(xiàn)auth模塊下的登錄注冊與注銷功能

    Django實現(xiàn)auth模塊下的登錄注冊與注銷功能

    這篇文章主要介紹了Django實現(xiàn)auth模塊下的登錄注冊與注銷功能,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • python跳出雙層循環(huán)的方法

    python跳出雙層循環(huán)的方法

    本文主要介紹了python跳出雙層循環(huán)的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Tornado Web Server框架編寫簡易Python服務器

    Tornado Web Server框架編寫簡易Python服務器

    這篇文章主要為大家詳細介紹了Tornado Web Server框架編寫簡易Python服務器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Python實現(xiàn)自動化網(wǎng)頁操作步驟

    Python實現(xiàn)自動化網(wǎng)頁操作步驟

    這篇文章主要介紹Python如何實現(xiàn)自動化網(wǎng)頁操作,文中有詳細的流程步驟和代碼示例,對我們的學習或工作有一定的幫助,需要的朋友可以參考下
    2023-06-06
  • python調(diào)用Delphi寫的Dll代碼示例

    python調(diào)用Delphi寫的Dll代碼示例

    這篇文章主要介紹了python調(diào)用Delphi寫的Dll代碼示例,具有一定參考價值,需要的朋友可以了解下。
    2017-12-12
  • Python的多態(tài)性實例分析

    Python的多態(tài)性實例分析

    這篇文章主要介紹了Python的多態(tài)性,以實例形式深入淺出的分析了Python在面向?qū)ο缶幊讨卸鄳B(tài)性的原理與實現(xiàn)方法,需要的朋友可以參考下
    2015-07-07
  • Python實現(xiàn)打印實心和空心菱形

    Python實現(xiàn)打印實心和空心菱形

    今天小編就為大家分享一篇Python實現(xiàn)打印實心和空心菱形,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • pandas滑動窗口學習筆記(shift, diff, pct_change)

    pandas滑動窗口學習筆記(shift, diff, pct_change)

    pandas中有3類窗口,分別是滑動窗口rolling?、擴張窗口expanding以及指數(shù)加權窗口ewm,下面就來詳細的介紹一下這三種的用法,感興趣的可以了解一下
    2024-03-03

最新評論