Django 開發人員犯的 10 大錯誤
已發表: 2022-03-11在本教程中,我們將研究 Django 開發人員經常犯的一些常見錯誤以及避免這些錯誤的方法。 即使您是熟練的 Django 開發人員,本教程也很有用,因為錯誤(例如維護無法管理的大設置或靜態資產中的命名衝突)不僅限於初次接觸 Django 的新開發人員。
Django 是一個免費的開源 Python Web 框架,它有助於解決常見的開發挑戰,並允許您構建靈活、結構良好的應用程序。 Django 有很多開箱即用的現代特性。 就我個人而言,管理、對象關係映射工具 (ORM)、路由和模板功能使 Django 成為我的首選,因為應用程序需要大量工作,雖然我像任何開發人員一樣享受我的工作,但我想花在這些基本的重複性任務上盡可能少的時間。 Django 允許您在不影響靈活性的情況下完成所有這些工作。
Django 的殺手級功能是一個強大的可配置管理界面,它會自動(自動?)從您的模型的模式和管理面板模型構建,讓您感覺像一個嚮導。 通過 Admin 界面,用戶可以配置很多東西,包括訪問控制列表 (ACL)、行級權限和操作、過濾器、訂單、小部件、表單、額外的 URL 幫助程序以及您可以想像的任何其他內容。 我相信每個應用程序都需要一個管理面板——如果還沒有,那麼您的基本應用程序需要一個管理面板只是時間問題。 使用 Django admin,您可以快速靈活地創建一個。
Django 有一個強大的 ORM,它可以與所有主要的數據庫一起工作。 由於它是惰性的,它僅在您需要時才訪問您的數據庫,這與其他 ORM 不同。 它支持您可以從 Python 源代碼中使用的所有主要 SQL 指令(和函數),並且由於 Python 的特性而感覺非常舒適。
Django 的模板引擎同時非常靈活和強大。 您可以使用許多標準過濾器和標籤,也可以為您的項目創建新的自定義過濾器和標籤。 Django 支持其他模板引擎以及 Django 模板,它提供了一個 API,可以通過標準的模板處理快捷功能輕鬆集成其他模板引擎。
Django 有很多其他的大特性,比如 URL 路由器,它可以解析傳入的請求並從路由器模式構建新的 URL。 總的來說,Django 框架是一種愉快的體驗,當您需要幫助時,只需閱讀文檔即可。
錯誤一:對項目依賴使用全局系統 Python 環境
不要將 Python 的全局環境用於項目依賴項,因為它會產生依賴項衝突。 Python 不能同時使用多個包版本。 如果不同的項目需要同一包的不同不兼容版本,這可能會成為問題。
這個錯誤通常是由不了解 Python 的環境隔離特性的新 Python 和 Django 開發人員犯的。
有很多方法可以隔離您的環境,但最常見的方法是:
- virtualenv:一個 Python 包,它生成一個 Python 環境文件夾,並具有用於 [de] 激活環境和管理環境中已安裝的 Python 包的腳本。 這是我最喜歡的方法,因為它是完成這項工作的最簡單方法。 通常,我在項目文件夾附近創建環境。
- virtualenvwrapper:一個 Python 包,可全局安裝並提供用於創建/刪除/激活/等的工具集。 虛擬環境。 所有虛擬環境都存儲在一個文件夾中(可以通過環境變量 WORKON_HOME 覆蓋)。 我看不出使用
virtualenvwrapper
代替virtualenv
有什麼好處。 - 虛擬機 (VM):沒有比專用於您的應用程序的整個虛擬機更大的隔離性了。 有很多工具可供選擇,包括 VirtualBox(免費)、VMware、Parallels 和 Proxmox(我個人最喜歡的,它有免費版本)。 結合像 Vagrant 這樣的 VM 自動化工具,這可能是一個非常強大的解決方案。
- 容器:在過去的幾年裡,我幾乎在每個項目中都使用了 Docker,尤其是在我從頭開始的每個新項目中。 Docker 是一個了不起的工具,它提供了很多功能,並且有很多用於容器自動化的第三方工具。 它具有層緩存功能,可以非常快速地重建容器。 在容器中,我使用全局系統 Python 環境,因為每個容器都有自己的文件系統,並且項目在高層上是隔離的。 Docker 允許新團隊成員更快地開始項目工作,特別是如果他們有 Docker 經驗。
如果你問我,我更喜歡virtualenv
Python 包和 Docker 容器來進行項目依賴隔離和管理。
錯誤 2:沒有在requirements.txt
文件中固定項目依賴項
每個新的 Python 項目都應該從一個 requirements.txt 文件和一個新的隔離環境開始。 通常,您通過pip/easy_install
安裝所有軟件包,但也不要忘記將它們添加到您的requirements.txt
文件中。 這使得更容易(可能更合適)在服務器上部署您的項目,或者讓團隊成員在他們自己的機器上引導項目。
此外,將依賴項的特定版本固定在requirements.txt
文件中同樣重要。 通常,不同版本的包提供不同的模塊、功能和功能參數; 即使是依賴項中的微小版本更改也可能會破壞您的包。 如果您的項目是實時的並且您已經定期安排部署,這是一個非常嚴重的問題,因為在沒有版本控制的情況下,您的構建系統將始終安裝最新的可用版本包。
始終固定您的包裝以進行生產! 就我個人而言,我使用了一個非常好的工具,叫做 pip-tools,它可以幫助我做到這一點。 它提供了一組命令行工具來幫助管理您的依賴關係。 它會自動生成一個requirements.txt
,其中不僅包含您的依賴項,還包含整個依賴項樹,其中包括您的依賴項的依賴項。
有時,您只想更新依賴項列表中的一些包(例如,只更新 Django/Flask/任何框架或實用程序),如果您使用“pip freeze”,您不知道哪些依賴項適用於哪些包,所以您無法升級依賴項。 但是,使用 pip-tools,它會根據您固定的依賴項自動固定包,因此它會自動解析需要更新的包。 作為獎勵,您還可以確切地知道哪個包來自哪個依賴項,因為它如何在requirements.txt
文件中用註釋標記它們。
要格外小心,備份您的依賴源文件也是一個好主意! 在您的文件系統、Git 管理的文件夾、S3 文件夾、FTP、SFTP 中保留一份副本——無論何時何地,但手頭都有。 在某些情況下,未列出的相對較小的包破壞了 npm 上的大量包。 Pip 提供了將所有必需的依賴項下載為源文件的工具,通過運行pip help download
了解更多信息。
錯誤 3:使用舊式 Python 函數而不是基於類的視圖
有時在應用程序的views.py
文件中使用一個小的 Python 函數是一個好主意,尤其是對於測試或實用程序視圖,但通常,您應該在應用程序中使用基於類的視圖 (CBV)。
CBV 是提供抽像類的通用視圖,這些抽像類實現由專業人員構建的常見 Web 開發任務並涵蓋所有常見行為。 它們有一個驚人的結構化 API,當您使用 CBV 時,您可以使用面向對象編程的所有優勢。 它使您的源代碼更加清晰易讀。 忘記使用 Django 標準視圖函數進行列表、CRUD 操作、表單處理等的痛苦。您只需為您的視圖擴展合適的 CBV 並覆蓋類屬性或函數(通常一個函數返回一個屬性,您可以在那裡添加任何邏輯在使用配置視圖行為的視圖函數而不是 CBV 的情況下,從您的源代碼製作意大利麵條。
例如,您可以在項目中使用不同的 mix-in,它們覆蓋基本的 CBV 行為以構建視圖上下文、在行級別檢查授權、從應用程序結構自動構建模板路徑、集成智能緩存等等。
我構建了名為 Django Template Names 的包,它根據應用程序名稱和視圖類名稱為您的視圖標準化模板名稱。 我每天都在使用它,它為我節省了很多時間來發明名稱。 只需將 mixin 放入您的 CBV—— class Detail(TemplateNames, DetailView):
——它就會開始工作! 當然,您可以覆蓋我的功能並添加移動響應模板、用戶代理的不同模板或任何其他您想要的東西。
錯誤 4:編寫胖視圖和瘦模型
在視圖而不是模型中編寫應用程序邏輯意味著您已將屬於模型的代碼寫入視圖,使其“胖”而模型“瘦”。
你應該寫胖模型,瘦視圖。
將邏輯分解為模型上的小方法。 這允許您在幾行代碼中從多個來源(管理界面 UI、前端 UI、API 端點、多個視圖)多次使用它,而不是複制粘貼大量代碼。 因此,下次您向用戶發送電子郵件時,請使用電子郵件功能擴展模型,而不是在控制器中編寫此邏輯。
這也使您的代碼更容易進行單元測試,因為您可以在一個地方測試電子郵件邏輯,而不是在發生這種情況的每個控制器中重複。
您可以在 Django Best Practices 項目中閱讀有關該問題的更多信息。 解決方案很簡單:編寫胖模型和瘦視圖,所以讓我們在您的下一個項目中進行(或重構您當前的項目)。
錯誤 5:一個巨大的、難以管理的設置文件
甚至新的 Django 項目設置文件也有很多設置。 在實際項目中,設置文件會增長到 700 多行配置,並且將變得難以維護,尤其是當您的開發、生產和暫存環境都需要自定義配置時。
您可以手動劃分配置文件並創建自定義加載器,但我想向您介紹一個很好且經過良好測試的 Python 包,Django Split Settings,它是我與人合著的。
該包提供了兩個函數—— optional
和include
——它們支持路徑的通配符並在相同的上下文中導入您的配置文件,從而使使用先前加載的文件中聲明的配置條目構建您的配置變得簡單。 它不會影響 Django 性能,您可以在任何項目中使用它。
查看最小配置示例:
from split_settings.tools import optional, include include( 'components/base.py', 'components/database.py', 'components/*.py', # the project different envs settings optional('envs/devel/*.py'), optional('envs/production/*.py'), optional('envs/staging/*.py'), # for any local settings optional('local_settings.py'), )
誤區六:多合一應用、不良應用結構、不正確的資源放置
任何 Django 項目都包含多個應用程序。 在 Django 表示法中,應用程序是一個 Python 包,其中至少包含__init__.py
和models.py
文件; 在最新的 Django 版本中,不再需要models.py
。 __init__.py
就足夠了。
Django 應用程序可以包含 Python 模塊、Django 特定模塊(視圖、URL、模型、管理、表單、模板標籤等)、靜態文件、模板、數據庫遷移、管理命令、單元測試等。 您應該使用簡單的邏輯將您的單體應用程序劃分為小的、可重用的應用程序。 您應該能夠用一兩個簡短的句子來描述應用程序的整個目的。 例如:“允許用戶通過電子郵件註冊和激活他們的帳戶。”

一個好主意是調用項目文件夾project
並將應用程序放在project/apps/
中。 然後,將所有應用程序依賴項放入它們自己的子文件夾中。
例子:
- 靜態文件:
project/apps/appname/static/appname/
- 模板標籤:
project/apps/appname/templatetags/appname.py
- 模板文件:
project/apps/appname/templates/appname/
始終在子文件夾中為應用程序名稱添加前綴,因為所有靜態文件夾都合併到一個文件夾中,如果兩個或多個應用程序有一個js/core.js
文件,則settings.INSTALLED_APPLICATIONS
中的最後一個應用程序將覆蓋以前的應用程序。 我曾經在我當前的項目中遇到過這個錯誤,並且失去了大約六個小時的調試時間,直到我意識到另一個開發人員已經覆蓋了static/admin/js/core.js
,因為該團隊正在實施一個自定義 SPA 管理面板並以相同的方式命名他們的文件。
這是一個包含大量資源和 Python 模塊的門戶應用程序的示例結構。
root@c5b96c395cfb:/test# tree project/apps/portal/ project/apps/portal/ ├── __init__.py ├── admin.py ├── apps.py ├── management │ ├── __init__.py │ └── commands │ ├── __init__.py │ └── update_portal_feeds.py ├── migrations │ └── __init__.py ├── models.py ├── static │ └── portal │ ├── css │ ├── img │ └── js ├── templates │ └── portal │ └── index.html ├── templatetags │ ├── __init__.py │ └── portal.py ├── tests.py ├── urls.py └── views.py 11 directories, 14 files
使用這樣的結構,您可以隨時將應用程序導出到另一個 Python 包中並再次使用它。 您甚至可以在 PyPi 中將其作為開源包發布,或將其移動到另一個文件夾。
你最終會得到一個像這樣的項目結構:
root@c5b96c395cfb:/test# tree -L 3 . ├── deploy │ ├── chef │ └── docker │ ├── devel │ └── production ├── docs ├── logs ├── manage.py ├── media ├── project │ ├── __init__.py │ ├── apps │ │ ├── auth │ │ ├── blog │ │ ├── faq │ │ ├── pages │ │ ├── portal │ │ └── users │ ├── conf │ ├── settings.py │ ├── static │ ├── templates │ ├── urls.py │ └── wsgi.py └── static └── admin ├── css ├── fonts ├── img └── js 25 directories, 5 files
當然,在實際項目中,它會更複雜,但這種結構使事情變得更簡單、更清晰。
錯誤 7: STATICFILES_DIRS
和STATIC_ROOT
迷惑新手 Django 開發人員
靜態文件是不會因應用程序的使用而改變的資產,例如 JavaScript、CSS、圖像、字體等。在 Django 中,它們僅在部署過程中被“收集”到公共目錄中。
在開發模式下——python python manage.py runserver
——Django 使用STATICFILES_FINDERS
設置搜索靜態文件。 默認情況下,它會嘗試在STATICFILES_DIRS
設置中列出的文件夾中查找請求的靜態文件。 如果失敗,Django 會嘗試使用django.contrib.staticfiles.finders.AppDirectoriesFinder
查找文件,該文件會在項目中每個已安裝應用程序的static
文件夾中查找。 這允許您編寫隨其自己的靜態文件一起提供的可重用應用程序。
在生產環境中,您使用像 Nginx 這樣的獨立 Web 服務器來提供靜態服務。 Web 服務器對 Django 項目應用程序結構或靜態文件分佈在哪些文件夾中一無所知。幸運的是,Django 為您提供了收集靜態管理命令python manage.py collectstatic
,它遍歷STATICFILES_FINDERS
並從應用程序static
復制所有靜態文件STATICFILES_DIRS
中列出的文件夾和文件夾到您在STATIC_ROOT
設置中指定的目錄中。 這允許使用與 Django 開發模式服務器相同的邏輯來解析靜態文件資源,並將所有靜態文件放在一個位置供您的 Web 服務器使用。
不要忘記在您的生產環境中運行collectstatic
!
錯誤 8:默認STATICFILES_STORAGE
,生產環境中的 Django 模板加載器
STATICFILES_STORAGE
先說生產環境資產管理。 如果我們使用“資產永不過期”政策(您可以在此處了解更多信息),我們可以提供最佳用戶體驗。 這意味著我們所有的靜態文件都應該被 Web 瀏覽器緩存數週、數月甚至數年。 換句話說,您的用戶應該只下載一次您的資產!
這很酷,我們可以在 Nginx 配置中為我們的靜態文件夾配置幾行代碼,但是緩存失效呢? 如果用戶只下載一次我們的資源,如果您更新了徽標、字體、JavaScript 或菜單中某個項目的文本顏色,會發生什麼情況? 要繞過這一點,您應該在每次部署時為我們的靜態文件生成唯一的 URL 和文件名!
我們可以簡單地通過使用 ManifestStaticFilesStorage 作為STATICFILES_STORAGE
(注意,哈希僅在DEBUG=false
模式下啟用)並運行上面討論的collectstatic
管理命令來實現。 這將減少對您的生產網站的資產請求計數,並使您的網站渲染速度更快。
緩存的 Django 模板加載器
另一個很酷的 Django 特性是緩存模板加載器,它不會在每次模板渲染時重新加載和解析模板文件。 模板解析是一項非常昂貴的操作,並且會佔用大量資源。 默認情況下,每個請求都會解析 Django 模板,但這很糟糕,尤其是在生產過程中,您可以在短時間內處理數千個請求。
查看cached.Loader
配置部分以獲取一個很好的示例和有關如何執行此操作的詳細信息。 不要在開發模式下使用加載器,因為它不會從文件系統重新加載已解析的模板; 您需要在每次模板更改時使用python manage.py startapp
重新啟動您的項目。 這在開發過程中可能很煩人,但它非常適合生產環境。
錯誤 9:實用程序或腳本的純 Python 腳本
Django 提供了一個非常好的特性,叫做管理命令。 只需使用它,而不是重新發明輪子並為您的項目實用程序編寫原始 Python 腳本。
另外,請查看 Django Extensions 包,它是 Django 自定義擴展的集合。 也許有人已經執行了你的命令! 已經有很多很多常見的任務命令。
錯誤 10:重新發明輪子
Django 和 Python 有數以千計的現成解決方案。 在你寫一些不獨特的東西之前嘗試谷歌搜索; 可能已經存在功能豐富的解決方案。
試著讓事情變得簡單。 谷歌第一! 如果您找到優質的軟件包,請安裝、配置、擴展和集成到您的項目中,當然,如果有機會,請為開源做出貢獻。
首先,這是我自己的 Django 公共包列表:
- Django Macros URL 通過使用宏可以輕鬆地在 Django 應用程序中編寫(和讀取)URL 模式。
- Django Templates Names 是一個小型組合,可讓您輕鬆標準化 CBV 模板名稱。
- django-split-settings 允許您將 Django 設置組織到多個文件和目錄中。 輕鬆覆蓋和修改設置。 在設置文件路徑中使用通配符並將設置文件標記為可選。
不要重複自己(幹)!
我真的很喜歡 DRY 方法; 這就是為什麼我創建 Django 骨架作為一個便利工具,它具有一些非常簡潔的開箱即用功能:
- 用於開發/生產的 Docker 映像,由 docker-compose 管理,可讓您輕鬆編排容器列表。
- 用於生產部署的簡單 Fabric 腳本。
- Django Split Settings 包的配置,包含基本和本地源的設置。
- Webpack 集成到項目中 - 只有
dist
文件夾會被 Django 通過collectstatic
命令收集。 - 配置了所有基本的 Django 設置和功能,如生產中的可緩存 Django 模板、散列靜態文件、集成調試工具欄、日誌記錄等。
它是一個現成的 Django Skeleton,可用於您的下一個從頭開始的項目,並有望通過引導您的項目為您節省大量時間。 Webpack 具有最少的基本配置,但它還安裝了預配置的 SASS 以處理.scss
文件。