django-distill
теперь есть веб-сайт. Подробнее читайте на:
django-distill
— генератор статических сайтов и издатель с минимальной конфигурацией для Django. Поддерживается большинство версий Django, однако рекомендуется использовать последние версии, включая выпуски Django 3.x. django-distill
начиная с версии 1.7 поддерживает только Python 3. Поддержка Python 2 прекращена. Если вам требуется поддержка Python 2, закрепите django-distill
до версии 1.6 в файле require.txt или Pipfile. Рекомендуется Python 3.6 или выше.
django-distill
расширяет существующие сайты Django возможностью экспорта полнофункциональных статических сайтов. Он подходит для таких сайтов, как блоги, которые имеют в основном статический интерфейс, но вы все равно хотите использовать CMS для управления контентом.
django-distill
перебирает URL-адреса в вашем проекте Django, используя простые в написании итерируемые функции для получения параметров для любых страниц, которые вы хотите сохранить в виде статического 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
Полный пример сайта, который создает статический блог и использует django-distill
с django-cachekiller
посредством непрерывного развертывания в Netlify, доступен здесь:
? meeb/django-distill-пример
Установить из пипа:
$ pip install django-distill
Добавьте django_distill
в INSTALLED_APPS
в файле settings.py
:
INSTALLED_APPS = [
# ... other apps here ...
'django_distill' ,
]
Вот и все.
django-distill
генерирует статические страницы, поэтому поддерживаются только представления, которые разрешают запросы GET
, возвращающие код состояния HTTP 200
.
Предполагается, что вы используете параметры URI, такие как /blog/123-abc
, а не параметры строки запроса, такие как /blog?post_id=123&title=abc
. Параметры строки запроса не имеют смысла для генерации статических страниц по очевидным причинам.
Статические медиа-файлы, такие как изображения и таблицы стилей, копируются из вашего статического медиа-каталога, определенного в STATIC_ROOT
. Это означает, что вам нужно будет запустить ./manage.py collectstatic
перед запуском ./manage.py distill-local
если вы внесли изменения в статический носитель. django-distill
не связывает этот запрос по умолчанию, однако вы можете включить его с помощью аргумента --collectstatic
.
Предполагая, что у вас есть существующий проект Django, отредактируйте urls.py
, включив в него функцию distill_path
, которая заменяет стандартную функцию path
Django и поддерживает новые аргументы ключевых слов distill_func
и distill_file
.
Аргумент distill_func
должен быть снабжен функцией или вызываемым классом, который возвращает итерируемый объект или None
.
Аргумент distill_file
является совершенно необязательным и позволяет переопределить URL-адрес, который в противном случае был бы сгенерирован из обратного регулярного выражения URL-адреса. Это позволяет вам переименовывать URL-адреса, такие как /example
на любое другое имя, например example.html
. Начиная с версии 0.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
s.
Вы также можете использовать функцию 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 ),
)
Если вы используете более старую версию Django серии 1.x, вы можете использовать вместо нее функцию 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 ),
)
Вы также можете использовать стандартное форматирование строк Python в distill_file
, чтобы при желании изменить путь к выходному файлу. Обратите внимание, что это не обновляет URL-адрес, используемый Django, поэтому, если вы используете это, убедитесь, что ваш шаблон 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, поэтому в какой-то момент функция distill_url
перестанет работать в будущем, когда сам Django 2.x устареет функции django.conf.urls.url
и django.urls.url
. Вы можете использовать distill_re_path
в качестве замены. Если вы сейчас создаете новый сайт, желательно использовать distill_path
или distill_re_path
.
Интернационализация поддерживается только для URL-адресов, содержимое страницы невозможно перевести динамически. По умолчанию ваш сайт будет создан с использованием значения LANGUAGE_CODE
в вашем settings.py
. Если вы также установите для settings.USE_I18N
значение True
, затем установите другие языковые коды в своем settings.DISTILL_LANGUAGES
и зарегистрируете URL-адреса с помощью i18n_patterns(...)
тогда ваш сайт будет создан на нескольких языках. Предполагается, что ваш многоязычный сайт работает так, как ожидалось, до добавления django-distill
.
Например, если вы установите settings.LANGUAGE_CODE = 'en'
ваш сайт будет создан на одном языке.
Если вместо этого в вашем settings.py
есть что-то подобное:
USE_I18N = True
DISTILL_LANGUAGES = [
'en' ,
'fr' ,
'de' ,
]
Также используя i18n_patterns
в вашем urls.py
, например:
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
на наличие языковых кодов.
Возможно, вам потребуется создать список всех URL-адресов, зарегистрированных с помощью django-distill
. Например, у вас есть статически сгенерированный блог с несколькими сотнями страниц, и вы хотите легко перечислить все URL-адреса в файле sitemap.xml
или другом подобном списке всех URL-адресов. Вы можете обернуть представление карты сайта в distill_path
а затем реплицировать всю логику генерации URL-адресов, импортировав представления distill_func
из вашего urls.py
и сгенерировав все это вручную, но, учитывая, что это довольно хлопотно, есть встроенный помощник для генерации всех ваших 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
Обратите внимание , что distilled_urls()
будет возвращать URL-адреса только после того, как все ваши URL-адреса в urls.py
будут загружены с помощью distill_path(...)
.
distill-local
После того, как вы обернули URL-адреса, которые хотите сгенерировать статически, вы можете создать полностью функционирующий статический сайт с помощью:
$ ./manage.py distill-local [optional /path/to/export/directory]
Под капотом это просто перебирает все URL-адреса, зарегистрированные с помощью distill_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/
использование этого флага создаст статическое перенаправление стиля 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/
использование этого флага создаст статическое перенаправление стиля 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 : словарь, как и settings.DATABASES
Django.DATABASES, поддерживает default
:
DISTILL_PUBLISH = {
'default' : {
... options ...
},
'some-other-target' : {
... options ...
},
}
DISTILL_SKIP_ADMIN_DIRS : bool, по умолчанию — True
DISTILL_SKIP_ADMIN_DIRS = True
Установите для DISTILL_SKIP_ADMIN_DIRS
значение False
если вы хотите, чтобы django-distill
также копировал статические файлы в каталоге static/admin
. Обычно они не требуются или нежелательны для статически созданных сайтов. Поведение по умолчанию — пропуск статических файлов администратора.
DISTILL_SKIP_STATICFILES_DIRS : список, по умолчанию []
DISTILL_SKIP_STATICFILES_DIRS = [ 'some_dir' ]
Установите DISTILL_SKIP_STATICFILES_DIRS
в список имен каталогов, которые вы хотите, чтобы django-distill
игнорировал каталоги в определенном вами каталоге static/
. Вы можете использовать это, чтобы игнорировать копирование каталогов, содержащих файлы из приложений, которые вы не используете, которые добавляются в ваш каталог static/
с помощью collect-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
, чтобы предотвратить возникновение CommandError
, когда запрос возвращает перенаправление 301 вместо ожидаемого кода ответа HTTP/200.
Начиная с версии 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
аналогичен синтаксису url.reverse
в Django. Полный интерфейс использования:
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 : публикация в контейнере хранилища BLOB-объектов Microsoft Azure. Требуется библиотека 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
Приветствуются все правильно отформатированные и разумные запросы на включение, проблемы и комментарии.