99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Django ORM模型的一點體會

發(fā)布時間:2017-03-25 14:42  回復(fù):0  查看:2368   最后回復(fù):2017-03-25 14:42  
使用Python Django 模型的話,一般都會用它自帶的 ORM Object-relational mapping )模型。這個 ORM 模型的設(shè)計比較簡單,學(xué)起來不會特別花時間。不過, Django ORM 模型有自己的一套語法,有時候會覺得別扭。這里聊一下我自己的體會,希望對大家 學(xué)習(xí)django有所幫助 。
   模型設(shè)計
  這一部分算處理得比較好的部分。Django 的數(shù)據(jù)模型的建立過程很簡單,就是繼承 django.db.models 中的 Model 類,然后給它增加屬性。每一個屬性可以對應(yīng)關(guān)系數(shù)據(jù)庫中的一個字段。比如在一個叫 myapp Django App 下,創(chuàng)建 models.py 文件:
   from django.db  import models class Person( models.Model):
  name = models.CharField( max_length=10)
  通過manage.py makemigrations migrate 命令,就可以執(zhí)行數(shù)據(jù)庫的遷移。上面的 name 屬性,就對應(yīng)了生成的 myapp_person 表中名為 "name" 的一列。這里的 max_length=10 對應(yīng)了限制條件:
   VARCHAR(10)
 ?。ㄔ?/span>MySQL V4 中,代表了 10 個字節(jié);在 MySQL V5 中,代表了 10 個字符。)
  除了上面的字符類型,其他常見的字段類型,在Django 都有對應(yīng)的 *Field 來表達,比如 TextField 、 DateField DateTimeField 、 IntegerField 、 DecimalField 。此外,還有一些常見的限制條件,除了上面的 max_length ,還有 default 、 unique 、 null 、 primary_key 等等。數(shù)字類型的限制條件有 max min 、 max_digits 、 decimal_places 。這些限制條件都通過參數(shù)的形式傳給屬性。有一些限制條件是 Django 提供的,并沒有數(shù)據(jù)庫層面的對應(yīng)物,比如 blank 。
  ( 當(dāng) blank 參數(shù)為真時,對應(yīng)字段可以為留為空白。 )
  在基本的模型設(shè)計上,Django ORM 沒有留什么坑。
   關(guān)系
  Django 中的一對一、多對一、多對多關(guān)系可以通過下面方式表達:
   from django.db  import models
   class Company( models.Model):
  name = models.CharField( max_length=10)
   class Group( models.Model):
  name = models.CharField( max_length=10)
   class Person( models.Model):
  name = models.CharField( max_length=10)
   class Customer( models.Model):
  name    = models.CharField( max_length=10)
  person  = models.OneToOneField(Person)
  company = models.ForeignKey(Company,  on_delete= models.CASCADE)
  groups  = models.ManyToManyField(Group)
  Customer 的定義中,用到一對一、多對一、多對多關(guān)系。它們分別通過 OneToOneField ForeignKey ManyToManyField 來實現(xiàn)。
  需要注意的是,在Django ORM 中,只能通過 ForeignKey 來定義多對一關(guān)系,不能顯示地定義一對多關(guān)系。但你可以使用模型對象的 *_set 語法來反向調(diào)用多對一關(guān)系。比如說:
   company.customer_set   #company 是一個 Company 的實例
  就可以根據(jù)一對多關(guān)系,調(diào)到該公司下的所有客戶。此外,多對多關(guān)系也可以用類似的方式反向調(diào)用,比如:
   group.customer_set
  此外,你還可以在模型中加入related_name 參數(shù),從而在反省調(diào)用時,改用 "*_set" 之外的其他名稱,比如:
   class  Customer(models.Model):
  person  = models.OneToOneField(Person)
  address = models.CharField(max_length=100)
  company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="customers")
  如果兩個模型之間有多個關(guān)系時,related_name 可以防止 *_set 重名。
  總的來說,上面的解決方案可以實現(xiàn)功能,并不影響使用。但我總是覺得這個解決方案有些丑陋。由于不能顯式地表達兩個模型之間的關(guān)系,模型之間的關(guān)系看起來不夠明了。特別是讀代碼時,第一個類定義完全沒法提示一對多的關(guān)系。我必須要看到了第二個類定義,才能搞明白兩個模型之間的關(guān)系。真希望有一種顯式說明關(guān)系的辦法,降低讀代碼時的認知負擔(dān)。
   查詢
  Django ORM 可以通過一些方法來實現(xiàn)。其中的很多方法返回的是 Django 自定義的 QuerySet 類的迭代器。 Python 看到迭代器時會懶惰求值,所以這些方法返回時并不會真正進行數(shù)據(jù)庫操作。這樣,多個方法串聯(lián)操作時,就避免了重復(fù)操作數(shù)據(jù)庫。返回 QuerySet 的常見方法包括:
   all() filter() exclude() annotate() order_by() reverse() distinct()
  ...
  對于依賴具體數(shù)據(jù)的操作,QuerySet 會求值。比如遍歷 QuerySet 時,就會先執(zhí)行數(shù)據(jù)庫操作。用 len() 獲得 QuerySet 長度時,也會造成 QuerySet 估值。此外 QuerySet 一些方法,比 get() 、 count() 、 earlist() 、 exists() 等,都會對 QuerySet 進行求值。因此,在寫程序時,要注意 QuerySet 求值的時間點,避免重復(fù)的數(shù)據(jù)庫操作。
  SQL WHERE 條件可以通過參數(shù)的形式來傳給方法。這些參數(shù)一般是 "[ 字段 ]__[ 運算符 ]" 的命名方式,比如:
   Customer.objects.filter(name__contains="abc")
  除了contains ,還有 in 、 gt 、 lt 、 startswith 、 date range 等等操作符,能實現(xiàn)的 WHERE 條件確實夠全的了。
  不過,這又是一個有點別扭的地方,即通過命名方式來控制查詢行為。我看過有的ORM 是用 lambda 的形式來表達 WHERE 條件,還有的會做一個類似于 contains() 的方法,都要比 Django ORM 的方式好看。如果是跨表查詢, Django 的方式就更丑了:
   Customer.objects.filter(company__name__contains="xxx")
  無限的雙下劃線啊……
   聚合
  Django 實現(xiàn)聚合的方式簡直是噩夢。貌似 ORM 對表達 GROUP BY 很無力,源代碼里的注釋就認輸了:
Django ORM模型的一點體會 
聚合的aggregate() annotate() 方法可以實現(xiàn)基本的功能,但稍微復(fù)雜一點,代碼就變得魔幻了:
Django ORM模型的一點體會 
看到一大串values() 、 annotate() 變來變?nèi)?,有沒有覺得頭暈?我覺得這種情況下,可以直接上原始的 SQL 查詢語句了,沒必要再自己折騰自己。
   F表達式和Q表達式
  F 表達式指代了一列,對于 update 操作時引用列的值有用。 Q 表達式代表了 WHERE 的一個條件,可以用于多個 WHERE 條件的連接。這些都是 Django ORM 用來彌補缺陷的。就拿 Q 表達式來說。查詢方法中跟多個參數(shù)的話,相當(dāng)于多個 WHERE 條件。這些條件會默認為 AND 關(guān)系。為了表達 OR NOT 關(guān)系, Django ORM 就造了個 Q 表達式,比如:
  filter( Q( name__contains="abc")|Q( name__startswith("xxx")))
 為了彌補缺陷,Django ORM 又增加了一種語法風(fēng)格。于是,學(xué)習(xí)路上又多了一個坑 ……
   總結(jié)
  總的來說,Django ORM 在實現(xiàn)基礎(chǔ)的數(shù)據(jù)庫操作方面沒問題。但如果需要構(gòu)建復(fù)雜的 SQL 語句,與其在 Django ORM 里繞來繞去,還不如直接用原始的 SQL 語句。這個是我最強烈的一個感受。
來源: 博客園
您還未登錄,請先登錄

熱門帖子

最新帖子

?