django-distill
现在有一个网站。阅读更多内容:
django-distill
是 Django 的最小配置静态站点生成器和发布器。支持大多数 Django 版本,但建议使用最新版本,包括 Django 3.x 版本。从 1.7 版本开始, django-distill
仅支持 Python 3。Python 2 支持已被删除。如果您需要 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 生成逻辑。将为您提取的 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
是可选的;如果未指定,谷歌库将按照此处描述的搜索顺序尝试其他身份验证方法: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
欢迎所有格式正确且合理的拉取请求、问题和评论。