Django後臺代碼質量改善建議集錦(一)

“寫代碼”技術的提高有兩個階段:第一個階段是讓代碼能實現功能、並且少出錯;第二個階段是讓代碼更易於理解、潛在問題更少。

第一個階段要怎麼做是非常清晰的,功能能實現,調用接口有合適的數據返回,就算完成了任務。到了第二階段,“應該怎麼做”這個問題就變得隱晦了,變得更加沒有標準答案了,因為每個人對“易於理解”這個要求的理解是不同的。雖然沒有標準答案,但是答案大綱還是有的,有一些規律或要求是被大多數人認可的。

本篇,我們就試著梳理一些“隱晦”的共識,讓在第二階段的讀者多一盞路燈。

1、定義Model類時,以一行數據的含義命名

舉個例子來說明這個問題:假設我們需要定義一張數據表,這張數據表中的每一行是A校期末考試中一名學生的成績,那麼這張數據表本身就是A校期末考試的總成績單。這時我們需要為這個數據表寫一個Model類,那麼這個Model類的名字應該是StudentScore(一個學生的成績),還是ScoreReport(學校成績單)呢?

答案應該是StudentScore。為什麼用StudentScore更合理呢?讓我們看一下我們通常是如何使用這個類的。

比如當我們想新建一條數據的時候,我們會這樣寫:

Django后台代码质量改善建议集锦(一)

這段代碼,即便是不懂Python的人來看,也可以大致猜出,這是在為張良創建一條學生成績記錄,並保存到數據庫。如果我們當初將Model命名為ScoreReport,代碼就變成了這樣:

Django后台代码质量改善建议集锦(一)

這段代碼,看的人會有這樣的困惑:創建了一個成績單,裡面寫入了一個學生的成績,那這個成績單是隻有一個學生的成績嗎?如果有第二個學生,需要再創建一個成績單嗎?還是report這個對象有一些方法,可以再添加第二個學生?

可以看出,命名為ScoreReport會給代碼閱讀者帶來很多困惑,不如命名為StudentScore表意清晰。在調用delete方法時這個表意的差別更加明顯,score.delete很清楚地表達了刪除的是一個學生的成績,如果用report.delete,讀者很容易誤解為把整個成績單都刪除了。

所以,給Model類取名字的時候要依據一行數據的含義命名,而不是依據整張表的含義命名。

用相似的思維方法,我們還可以得出一個結論,就是“給Model類取名字的時候要用單數,而不是複數。”為什麼這樣?大家可以自己思考一下。

2、變量命名單複數一定要分清

這個其實是PEP8標準中要求的一部分,這裡單獨拿出來說,是因為很多同學主要靠工具來完成PEP8的格式化,而工具是不會為你糾正這個命名問題的。

Python由於其動態性,編輯器往往沒法告訴你某個變量是什麼類型,這實際上增加了代碼閱讀者理解代碼數據結構的難度,也對Python變量的命名提出了更為苛刻的要求。

舉個例子,我們在Django中經常需要查詢某表的很多行,然後遍歷這些行,對它們依次進行一些操作,一個比較典型的代碼是這樣的:

Django后台代码质量改善建议集锦(一)

這裡有幾個要點:

  1. 通過Model.objects.filter(...)這個句式得到的是多行的一種集合。所以這個句式的結果變量應該用複數。

  2. 因為集合變量名用了複數,在for循環中就不必動腦筋再想一個臨時變量了,直接將複數變單數作為臨時變量名。

  3. 這樣的命名方式也很容易可以看出score和scores之間是什麼樣的關係。

但是有些同學不注意變量的單複數,經常會寫出這樣的代碼:

Django后台代码质量改善建议集锦(一)

這樣的代碼,讓閱讀者搞不清楚score到底是一個成績還是多個成績?obj和score是什麼關係?如果相同函數中還有另外一個查詢,要如何命名?叫obj2?總體來說,歧義太多,讓人困惑。

即便是前面一種比較好的命名方式,小編也認為仍有改進的空間,比如可以把scores改叫score_queryset。這樣改更加突出了這個變量的類型,是一個QuerySet,這樣也可以提醒編碼者,這個變量是不能JSON化的,是不能直接通過HttpResponse返回的。

3、儘量少用=True

很多新手分不清blank=True和=True有什麼區別,導致胡亂使用,這裡我們解釋一下:

  1. blank=True表示該字段在代碼層面可不可以不傳值,如果blank=False(默認情況),但是通過Model創建對象時卻沒有給該字段賦值,Django會報錯。

  2. =True表示該字段在數據庫層面可不可以不傳值,如果=False(默認情況),寫入數據庫時該字段沒有賦值,或者賦值為None,則數據庫會報錯。

那為什麼說要儘量少用=True呢?是因為數據庫表的一列中只要有一個值,那麼這一列的索引都會失效。會導致數據庫查詢性能的大幅下降。

我們再反過來想,當你用了blank=True或者=True的時候,你實際上想表達什麼意思?你想的是這個字段可以不傳值。而我們知道數據庫中的一列無論你傳不傳值,本質上都是有值的,只不過這個值可能是。而由於會導致索引失效,所以我們希望在你不傳值的時候,數據庫中寫入的值最好不要是。那麼想到這裡,你就會意識到,你應該自己設置一個默認值。所以當你想寫blank=True,=True的時候,其實你更應該寫blank=True, default=XXX。這樣,當你不傳值的時候,數據庫中存儲的是一個你意料中特殊值。如果當前定義的這個字段是整數,那麼這個特殊值經常是0;如果當前定義的這個字段是字符串,那麼這個特殊值經常是“”(空字符串)。無論如何,不是就好。

當然,也不是沒有例外。ForeignKey字段如果允許不填值,blank=True並且=True是可以接受的。因為雖然ForeignKey底層本質上是一個整數,但是這個整數如果你填寫非正整數,Django在取值的時候會報錯。所以不得已地,這裡可以用下=True。(自我安慰一下,ForeignKey裡需要=True的場景還是不太多、比較少)

Django后台代码质量改善建议集锦(一)

今天先總結到這裡,未完待續~~ 如果你也有什麼想說的,歡迎在下方留言哦。


分享到:


相關文章: