django-distill
現在有一個網站。閱讀更多內容:
django-distill
是 Django 的最小配置靜態網站產生器和發佈器。支援大多數 Django 版本,但建議使用最新版本,包括 Django 3.x 版本。從 1.7 版本開始, django-distill
僅支援 Python 3。如果您需要 Python 2 支持,請在您的requirements.txt 或 Pipfile 中將django-distill
固定到版本 1.6。建議使用Python 3.6或以上版本。
django-distill
擴展了現有的 Django 站點,能夠匯出功能齊全的靜態站點。它適用於部落格等具有大部分靜態前端但您仍希望使用 CMS 來管理內容的網站。
django-distill
使用易於編寫的可迭代函數迭代 Django 專案中的 URL,為您想要儲存為靜態 HTML 的任何頁面產生參數。這些靜態檔案可以自動上傳到儲存桶式遠端容器,例如 Amazon S3、Googe Cloud Files、Microsoft Azure Storage,或作為專案的完全工作的本機靜態版本寫入本機目錄。網站生成或蒸餾過程可以輕鬆整合到 CI/CD 工作流程中,以便在提交時自動部署靜態網站。 django-distill
可以定義為 Django 的擴展,使 Django 專案與「Jamstack」風格的網站架構相容。
django-distill
直接插入現有的 Django 框架,無需編寫自訂渲染器或其他更詳細的程式碼。您還可以將django-distill
與現有動態網站集成,並只為一小部分頁面而不是整個網站產生靜態頁面。
對於 CDN 上的靜態文件,您可以使用以下「快取破壞程式」庫,以便在推送變更時實現快速靜態媒體更新:
? meeb/django-cachekiller
有一個完整的範例站點,它創建一個靜態博客,並透過在 Netlify 上持續部署來使用django-distill
和django-cachekiller
:
? meeb/django-distill-範例
從 pip 安裝:
$ pip install django-distill
將django_distill
加入settings.py
中的INSTALLED_APPS
中:
INSTALLED_APPS = [
# ... other apps here ...
'django_distill' ,
]
就是這樣。
django-distill
產生靜態頁面,因此僅支援允許返回HTTP 200
狀態代碼的GET
請求的視圖。
假設您使用的是 URI 參數(例如/blog/123-abc
,而不是查詢字串參數(例如/blog?post_id=123&title=abc
。由於顯而易見的原因,查詢字串參數對於靜態頁面產生沒有意義。
靜態媒體檔案(例如圖像和樣式表)是從STATIC_ROOT
中定義的靜態媒體目錄複製的。這表示如果您對靜態媒體進行了更改,則需要在運行./manage.py distill-local
之前運行./manage.py collectstatic
。 django-distill
不會按照設計連結此請求,但是您可以使用--collectstatic
參數啟用它。
假設您有一個現有的 Django 項目,請編輯urls.py
以包含distill_path
函數,該函數會取代 Django 的標準path
函數並支援新的關鍵字參數distill_func
和distill_file
。
distill_func
參數應該提供一個傳回 iterable 或None
函數或可呼叫類別。
distill_file
參數完全是可選的,可讓您覆寫否則從 URL 正規表示式的反向產生的 URL。這允許您將 URL(如/example
重新命名為任何其他名稱(如example.html
。從 v0.8 開始,任何以斜線/
結尾的 URI 都會自動修改為以/index.html
結尾。您可以在distill_file
中使用格式字串參數來自訂檔名,URL 中的參數值將會被替換,例如{}
代表位置參數,或{param_name}
代表命名參數。
理論部落格應用程式的蒸餾設定範例如下:
# Replaces the standard django.conf.path, identical syntax
from django_distill import distill_path
# Views and models from a theoretical blogging app
from blog . views import PostIndex , PostView , PostYear
from blog . models import Post
def get_index ():
# The index URI path, '', contains no parameters, named or otherwise.
# You can simply just return nothing here.
return None
def get_all_blogposts ():
# This function needs to return an iterable of dictionaries. Dictionaries
# are required as the URL this distill function is for has named parameters.
# You can just export a small subset of values here if you wish to
# limit what pages will be generated.
for post in Post . objects . all ():
yield { 'blog_id' : post . id , 'blog_title' : post . title }
def get_years ():
# You can also just return an iterable containing static strings if the
# URL only has one argument and you are using positional URL parameters:
return ( 2014 , 2015 )
# This is really just shorthand for ((2014,), (2015,))
urlpatterns = (
# e.g. / the blog index
distill_path ( '' ,
PostIndex . as_view (),
name = 'blog-index' ,
# Note that for paths which have no paramters
# distill_func is optional
distill_func = get_index ,
# '' is not a valid file name! override it to index.html
distill_file = 'index.html' ),
# e.g. /post/123-some-post-title using named parameters
distill_path ( 'post/<int:blog_id>-<slug:blog_title>.html' ,
PostView . as_view (),
name = 'blog-post' ,
distill_func = get_all_blogposts ),
# e.g. /posts-by-year/2015 using positional parameters
# url ends in / so file path will have /index.html appended
distill_path ( 'posts-by-year/<int:year>/' ,
PostYear . as_view (),
name = 'blog-year' ,
distill_func = get_years ),
)
進行上述變更後,您的網站仍將保持相同的功能。在內部, distill_func
和distill_file
參數被刪除,URL 傳回 Django 進行正常處理。這不會對運行時效能產生影響,因為這種情況僅在啟動應用程式時發生一次。
如果您的路徑沒有 URI 參數,例如/
或/some-static-url
則不必指定distill_func
參數(如果您不想)。對於沒有參數的路徑, distill_func
總是傳回None
,這被設定為distill_func
的預設行為。
您也可以使用distill_re_path
函數,它取代預設的django.urls.re_path
函數。其用法與上面相同:
from django_distill import distill_re_path
urlpatterns = (
distill_re_path ( r'some/regex'
SomeOtherView . as_view (),
name = 'url-other-view' ,
distill_func = some_other_func ),
)
如果您使用的是 1.x 系列中舊版的 Django,您可以使用distill_url
函數來取代django.conf.urls.url
或django.urls.url
函數。其用法與上面相同:
from django_distill import distill_url
urlpatterns = (
distill_url ( r'some/regex'
SomeView . as_view (),
name = 'url-view' ,
distill_func = some_func ),
)
您也可以在distill_file
中使用標準 Python 字串格式,以便根據需要變更檔案的輸出檔案路徑。請注意,這不會更新 Django 使用的 URL,因此如果您使用它,請確保您的path
模式與distill_file
模式匹配,否則您的連結可能無法在 Django 中運作。一個例子:
# Override file path with parameters. Values are taken from the URL pattern
urlpatterns = (
distill_path ( 'post/<int:blog_id>-<slug:blog_title>.html' ,
PostView . as_view (),
name = 'blog-post' ,
distill_func = get_all_blogposts ,
distill_file = "post/{blog_id}-{blog_title}.html"
)
django-distill
呈現為靜態頁面的所有視圖都必須傳回 HTTP 200 狀態碼。如果您出於任何原因需要渲染一個不傳回 HTTP 200 狀態代碼的視圖,例如您也想要靜態產生 404 頁面,該頁面有一個(正確)傳回 HTTP 404 狀態代碼的視圖,您可以使用distill_status_codes
視圖的可選參數。例如:
from django_distill import distill_url
urlpatterns = (
distill_url ( r'some/regex'
SomeView . as_view (),
name = 'url-view' ,
distill_status_codes = ( 200 , 404 ),
distill_func = some_func ),
)
可選的distill_status_codes
參數接受狀態代碼元組作為整數,允許視圖返回而不引發錯誤。預設情況下,該值設定為(200,)
但如果您的網站需要,您可以覆寫它。
django-distill
將鏡像您安裝的 Django 版本支援的任何內容,因此在將來某個時候,當 Django 2.x 本身貶值django.conf.urls.url
和django.urls.url
函數時, distill_url
函數將停止工作。您可以使用distill_re_path
作為直接替代品。如果您現在正在建立新站點,建議使用distill_path
或distill_re_path
。
僅支援 URL 國際化,頁面內容無法動態翻譯。預設情況下,您的網站將使用settings.py
中的LANGUAGE_CODE
值產生。如果您也將settings.USE_I18N
設為True
,然後在settings.DISTILL_LANGUAGES
值中設定其他語言程式碼並使用i18n_patterns(...)
註冊 URL,那麼您的網站將以多種語言產生。這假設您的多語言網站在添加django-distill
之前按預期工作。
例如,如果您設定settings.LANGUAGE_CODE = 'en'
您的網站將以一種語言產生。
如果您的settings.py
中有類似的內容:
USE_I18N = True
DISTILL_LANGUAGES = [
'en' ,
'fr' ,
'de' ,
]
同時在urls.py
中也使用i18n_patterns
,如下所示:
from django . conf . urls . i18n import i18n_patterns
from django_distill import distill_path
urlpatterns = i18n_patterns (
distill_path ( 'some-file.html' ,
SomeView . as_view (),
name = 'i18n-view' ,
distill_func = some_func
)
)
然後你的檢視會產生為/en/some-file.html
、 /fr/some-file.html
和/de/some-file.html
。這些 URL 應該已經可以在您的網站上使用(並被翻譯)。 django-distill
不做任何翻譯魔法,它只是呼叫帶有語言代碼前綴的 URL。
注意雖然預設建議的方法是使用settings.DISTILL_LANGUAGES
來保持獨立, django-distill
也會檢查settings.LANGUAGES
中的語言程式碼。
您可能需要產生使用django-distill
註冊的所有 URL 的清單。例如,您有一個包含數百頁的靜態生成的博客,並且您希望在sitemap.xml
或所有 URL 的其他類似列表中輕鬆列出所有 URL。您可以將網站地圖視圖包裝在distill_path
中,然後透過從urls.py
匯入視圖distill_func
並手動產生這些內容來複製所有URL 生成邏輯,但考慮到這相當麻煩,有一個內建的幫助程式可以產生所有您的URL 產生邏輯。
from django_distill import distilled_urls
for uri , file_name in distilled_urls ():
# URI is the generated, complete URI for the page
print ( uri ) # for example: /blog/my-post-123/
# file_name is the actual file name on disk, this may be None or a string
print ( file_name ) # for example: /blog/my-post-123/index.html
請注意,只有在使用distill_path(...)
載入urls.py
中的所有 URL 後, distilled_urls()
才會傳回 URL。
distill-local
命令一旦您封裝了要靜態產生的 URL,現在就可以使用以下命令產生一個功能完整的靜態網站:
$ ./manage.py distill-local [optional /path/to/export/directory]
在底層,這只是迭代所有用distill_url
註冊的 URL,並使用 Django 測試框架的一部分來欺騙請求,為它們產生頁面。呈現網站頁面後,就會複製STATIC_ROOT
中的檔案。目標目錄中的現有同名檔案將被替換,孤立檔案將被刪除。
distill-local
支援以下可選參數:
--collectstatic
:在渲染之前在您的網站上自動執行collectstatic
,這只是一個快捷方式,可以節省您輸入額外的命令。
--quiet
:停用除詢問確認問題之外的所有輸出。
--force
:對所有確認問題假設「是」。
--exclude-staticfiles
:完全不複製任何靜態文件,僅渲染 Django 視圖的輸出。
--parallel-render [number of threads]
:在多個線程上並行渲染文件,這可以加快渲染速度。預設為1
線程。
--generate-redirects
:嘗試產生儲存在django.contrib.redirects
應用程式中的靜態重定向。如果您有從/old/
到/new/
重定向,使用此標誌將在 /old/index.html 處建立靜態 HTML <meta http-equiv="refresh" content="...">
樣式/old/index.html
到/new/
。
注意:如果任何視圖包含 Python 錯誤,則渲染將失敗,然後堆疊追蹤將列印到終端,並且渲染命令將以狀態代碼 1 退出。
distill-publish
命令$ ./manage.py distill-publish [optional destination here]
如果您至少配置了一個發布目標(請參閱下文),則可以使用distill-publish
指令將網站發佈到遠端位置。
這將執行完全同步,刪除生成的靜態網站中不再存在的任何遠端文件,並上傳任何新的或更改的文件。網站發佈時會先在本地建立一個臨時目錄,發布後該目錄將被刪除。將透過PUBLIC_URL
請求來檢查每個文件是否已正確發布。
distill-publish
支援以下可選參數:
--collectstatic
:在渲染之前在您的網站上自動執行collectstatic
,這只是一個快捷方式,可以節省您輸入額外的命令。
--quiet
:停用除詢問確認問題之外的所有輸出。
--force
:對所有確認問題假設「是」。
--exclude-staticfiles
:完全不複製任何靜態文件,僅渲染 Django 視圖的輸出。
--skip-verify
:不測試檔案是否正確上傳到伺服器。
--ignore-remote-content
:不取得遠端檔案清單。這意味著將上傳所有文件,並且不會刪除現有的遠端文件。如果遠端伺服器上有很多文件,並且您知道要更新其中大部分文件,並且不關心舊文件是否保留在伺服器上,那麼這會很有用。
--parallel-publish [number of threads]
: 在多個線程上並行發布文件,這可以加快發布速度。預設為1
線程。
--parallel-render [number of threads]
:在多個線程上並行渲染文件,這可以加快渲染速度。預設為1
線程。
--generate-redirects
:嘗試產生儲存在django.contrib.redirects
應用程式中的靜態重定向。如果您有從/old/
到/new/
重定向,使用此標誌將在 /old/index.html 處建立靜態 HTML <meta http-equiv="refresh" content="...">
樣式/old/index.html
到/new/
。
請注意,這意味著如果您使用--force
和--quiet
,則輸出目錄將刪除不屬於網站匯出的所有文件,而無需任何確認。
注意:如果任何視圖包含 Python 錯誤,則渲染將失敗,然後堆疊追蹤將列印到終端,並且渲染命令將以狀態代碼 1 退出。
distill-test-publish
命令$ ./manage.py distill-test-publish [optional destination here]
這將連接到您的發布目標,對其進行身份驗證,上傳隨機命名的文件,驗證它是否存在於PUBLIC_URL
上,然後再次刪除它。用它來檢查您的發佈設定是否正確。
distill-test-publish
沒有參數。
您可以設定以下可選的settings.py
變數:
DISTILL_DIR :字串,匯出到的預設目錄:
DISTILL_DIR = '/path/to/export/directory'
DISTILL_PUBLISH :字典,像 Django 的settings.DATABASES
一樣,支援default
:
DISTILL_PUBLISH = {
'default' : {
... options ...
},
'some-other-target' : {
... options ...
},
}
DISTILL_SKIP_ADMIN_DIRS :布林值,預設為True
DISTILL_SKIP_ADMIN_DIRS = True
如果您希望django-distill
也複製static/admin
目錄中的靜態文件,請將DISTILL_SKIP_ADMIN_DIRS
設為False
。通常,靜態產生的網站不需要或不需要這些。預設行為是跳過靜態管理文件。
DISTILL_SKIP_STATICFILES_DIRS :列表,預設為[]
DISTILL_SKIP_STATICFILES_DIRS = [ 'some_dir' ]
將DISTILL_SKIP_STATICFILES_DIRS
設定為您希望django-distill
忽略定義的static/
目錄中的目錄名稱的清單。您可以使用它來忽略複製包含來自您不使用的應用程式的檔案的目錄,這些檔案透過collect-static
捆綁到您的static/
目錄中。例如,如果將DISTILL_SKIP_STATICFILES_DIRS
設定為['some_dir']
則會跳過靜態檔案目錄static/some_dir
。
DISTILL_LANGUAGES :列表,預設為[]
DISTILL_LANGUAGES = [
'en' ,
'fr' ,
'de' ,
]
將DISTILL_LANGUAGES
設定為嘗試呈現 URL 的語言代碼清單。有關更多詳細信息,請參閱“國際化”部分。
如果您使用的是支援 HTTPS 的本機開發環境,您可能需要將SECURE_SSL_REDIRECT = False
新增至您的settings.py
中,以防止在要求傳回 301 重新導向而不是預期的 HTTP/200 回應碼時引發CommandError
。
從django-distill
版本3.0.0
開始,您可以使用django_distill.renderer.render_single_file
方法使用django_distill
將單一檔案寫入磁碟。這對於將單一文件寫入磁碟非常有用,例如,您有一個 Django 站點,其中在django_distill
寫入的目錄中有一些靜態文件,但該站點的其餘部分是普通的動態 Django 站點。每次儲存模型實例時,您都可以更新靜態 HTML 檔案。您可以使用帶有訊號的單一檔案寫入來實現此目的。例如:
# in models.py
from django . db . models . signals import post_save
from django . dispatch import receiver
from django_distill . renderer import render_single_file
@ receiver ( post_save , sender = SomeBlogPostModel )
def write_blog_post_static_file_post_save ( sender , ** kwargs ):
render_single_file (
'/path/to/output/directory' ,
'blog-post-view-name' ,
blog_id = sender . pk ,
blog_slug = sender . slug
)
render_single_file
的語法類似 Django 的url.reverse
。完整的使用介面為:
render_single_file (
'/path/to/output/directory' ,
'view-name-set-in-urls-py' ,
* view_args ,
** view_kwargs
)
例如,如果您的部落格文章 URL 定義為:
# in urls.py
distill_path ( 'post/<int:blog_id>_<slug:blog_slug>.html' ,
PostView . as_view (),
name = 'blog-post' ,
distill_func = get_all_blogposts ),
你的用法是:
render_single_file (
'/path/to/output/directory' ,
'blog-post' ,
blog_id = 123 ,
blog_slug = 'blog-title-slug' ,
)
這會將/post/123_blog-title-slug.html
的內容寫入/path/to/output/directory
作為檔案/path/to/output/directory/post/123_blog-title-slug.html
。請注意,如果任何必需的子目錄(本例中/path/to/output/directory/post
)尚不存在,則將自動建立它們。所有django-distill
規則均適用,例如以/
結尾的 URL 將儲存為/index.html
以對磁碟上的實體檔案有意義。
另請注意, render_single_file
只能匯入並使用到已初始化的 Django 專案中。
您可以透過後端自動將網站發佈到各種支援的遠端目標,就像透過變更後端資料庫引擎將 MySQL、SQLite、PostgreSQL 等與 Django 一起使用一樣。目前django-distill
支援的引擎有:
django_distill.backends.amazon_s3 :發佈到 Amazon S3 儲存桶。需要 Python 函式庫boto3
( $ pip install django-distill[amazon]
)。此儲存桶必須已存在(使用 AWS 控制面板)。選項:
'some-s3-container' : {
'ENGINE' : 'django_distill.backends.amazon_s3' ,
'PUBLIC_URL' : 'http://.../' ,
'ACCESS_KEY_ID' : '...' ,
'SECRET_ACCESS_KEY' : '...' ,
'BUCKET' : '...' ,
'ENDPOINT_URL' : 'https://.../' , # Optional, set to use a different S3 endpoint
'DEFAULT_CONTENT_TYPE' : 'application/octet-stream' , # Optional
},
django_distill.backends.google_storage :發佈到 Google Cloud Storage 儲存桶。需要 Python 函式庫google-api-python-client
和google-cloud-storage
( $ pip install django-distill[google]
)。此儲存桶必須已存在並設定為託管公共靜態網站(使用 Google Cloud 控制面板)。選項:
'some-google-storage-bucket' : {
'ENGINE' : 'django_distill.backends.google_storage' ,
'PUBLIC_URL' : 'https://storage.googleapis.com/[bucket.name.here]/' ,
'BUCKET' : '[bucket.name.here]' ,
'JSON_CREDENTIALS' : '/path/to/some/credentials.json' ,
},
請注意, JSON_CREDENTIALS
是可選的;如果未指定,Google庫將按照此處所述的搜尋順序嘗試其他驗證方法:https://cloud.google.com/docs/authentication/application-default-credentials(例如GOOGLE_APPLICATION_CREDENTIALS
環境變數、附加服務帳戶等) 。
django_distill.backends.microsoft_azure_storage :發佈到 Microsoft Azure Blob 儲存容器。需要 Python 函式庫azure-storage-blob
( $ pip install django-distill[microsoft]
)。儲存帳戶必須已存在並設定為託管公共靜態網站(使用 Microsoft Azure 控制面板)。選項:
'some-microsoft-storage-account' : {
'ENGINE' : 'django_distill.backends.microsoft_azure_storage' ,
'PUBLIC_URL' : 'https://[storage-account-name]...windows.net/' ,
'CONNECTION_STRING' : '...' ,
},
請注意,每個 Azure 儲存帳戶都支援一個使用神奇容器$web
的靜態網站, django-distill
將嘗試發佈您的網站。
有一個最小的測試套件,您可以透過關閉此儲存庫來運行它,在requirements.txt
中安裝所需的依賴項,然後執行:
# ./run-tests.py
歡迎所有格式正確且合理的拉取請求、問題和評論。