Django ORM模型 想說愛你不容易

2021-09-08 12:33:32 字數 3857 閱讀 5708

from django.db import

models

class

person(models.model):

name = models.charfield(max_length=10)

varchar(10)
(在mysql v4中,代表了10個位元組;在mysql v5中,代表了10個字元。)

除了上面的字元型別,其他常見的字段型別,在django都有對應的*field來表達,比如textfield、datefield、datetimefield、integerfield、decimalfield。此外,還有一些常見的限制條件,除了上面的max_length,還有default、unique、null、primary_key等等。數字型別的限制條件有max、min、max_digits、decimal_places。這些限制條件都通過引數的形式傳給屬性。有一些限制條件是django提供的,並沒有資料庫層面的對應物,比如blank。

(當blank引數為真時,對應字段可以為留為空白。)

在基本的模型設計上,django orm沒有留什麼坑。

django中的一對

一、多對

一、多對多關係可以通過下面方式表達:

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的定義中,用到一對

一、多對

一、多對多關係。它們分別通過onetoonefield、foreignkey和manytomanyfield來實現。

需要注意的是,在django orm中,只能通過foreignkey來定義多對一關係,不能顯示地定義一對多關係。但你可以使用模型物件的*_set語法來反向呼叫多對一關係。比如說:

company.customer_set   #

company是乙個company的例項

就可以根據一對多關係,調到該公司下的所有客戶。此外,多對多關係也可以用類似的方式反向呼叫,比如:

group.customer_set
此外,你還可以在模型中加入related_name引數,從而在反省呼叫時,改用"*_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

")

如果兩個模型之間有多個關係時,related_name可以防止*_set重名。

總的來說,上面的解決方案可以實現功能,並不影響使用。但我總是覺得這個解決方案有些醜陋。由於不能顯式地表達兩個模型之間的關係,模型之間的關係看起來不夠明了。特別是讀**時,第乙個類定義完全沒法提示一對多的關係。我必須要看到了第二個類定義,才能搞明白兩個模型之間的關係。真希望有一種顯式說明關係的辦法,降低讀**時的認知負擔。

django orm可以通過一些方法來實現。其中的很多方法返回的是django自定義的queryset類的迭代器。python看到迭代器時會懶惰求值,所以這些方法返回時並不會真正進行資料庫操作。這樣,多個方法串聯操作時,就避免了重複運算元據庫。返回queryset的常見方法包括:

all()

filter()

exclude()

annotate()

order_by()

reverse()

distinct()

...

對於依賴具體資料的操作,queryset會求值。比如遍歷queryset時,就會先執行資料庫操作。用len()獲得queryset長度時,也會造成queryset估值。此外queryset一些方法,比get()、count()、earlist()、exists()等,都會對queryset進行求值。因此,在寫程式時,要注意queryset求值的時間點,避免重複的資料庫操作。

sql的where條件可以通過引數的形式來傳給方法。這些引數一般是"[字段]__[運算子]"的命名方式,比如:

customer.objects.filter(name__contains="

abc")

除了contains,還有in、gt、lt、startswith、date、range等等操作符,能實現的where條件確實夠全的了。

不過,這又是乙個有點彆扭的地方,即通過命名方式來控制查詢行為。我看過有的orm是用lambda的形式來表達where條件,還有的會做乙個類似於contains()的方法,都要比django orm的方式好看。如果是跨表查詢,django的方式就更醜了:

customer.objects.filter(company__name__contains="

***")

無限的雙下劃線啊……

django實現聚合的方式簡直是噩夢。貌似orm對表達group by很無力,源**裡的注釋就認輸了:

聚合的aggregate()和annotate()方法可以實現基本的功能,但稍微複雜一點,**就變得魔幻了:

看到一大串values()、annotate()變來變去,有沒有覺得頭暈?我覺得這種情況下,可以直接上原始的sql查詢語句了,沒必要再自己折騰自己。

f表示式指代了一列,對於update操作時引用列的值有用。q表示式代表了where的乙個條件,可以用於多個where條件的連線。這些都是django orm用來彌補缺陷的。就拿q表示式來說。查詢方法中跟多個引數的話,相當於多個where條件。這些條件會預設為and關係。為了表達or和not關係,django orm就造了個q表示式,比如:

filter(q(name__contains="

abc")|q(name__startswith("

***")))

為了彌補缺陷,django orm又增加了一種語法風格。於是,學習路上又多了乙個坑……

總的來說,django orm在實現基礎的資料庫操作方面沒問題。但如果需要構建複雜的sql語句,與其在django orm裡繞來繞去,還不如直接用原始的sql語句。這個是我最強烈的乙個感受。當然,django orm還是可用的工具。我寫這篇文章的目的,是提醒大家不要誤把糟糕的設計當做精巧的語法。

Django ORM模型 想說愛你不容易

from django.db import models class person models.model name models.charfield max length 10 varchar 10 在mysql v4中,代表了10個位元組 在mysql v5中,代表了10個字元。除了上面的字元...

IT 想說愛你不容易

檢查了半天,也跟蹤了伺服器端的執行日誌,沒有發現什麼問題,重啟伺服器程序,繼續跟蹤排程程序和執行程序,依舊沒有看出什麼問題,後來根據日誌中的select語句又到資料庫裡面查了一下,嘿!居然沒有資料。估計是命令解析的時候出了錯誤,看來是程式問題了,在伺服器上找到執行程序的源程式,make clean ...

crontab,想說愛你不easy

跑自己主動化指令碼的機器連不上toastserver了,僅僅能自己寫個指令碼每天跑了。當然要放在crontab裡了。5 3 sh nosecron.sh 第二天過來一看結果,fail了大半。然後在log的最前面有一句 warning failed to execute tcpdump.check i...