django-distill
agora tem um site. Leia mais em:
django-distill
é um gerador e editor de sites estáticos de configuração mínima para Django. A maioria das versões do Django são suportadas, no entanto, versões atualizadas são recomendadas, incluindo as versões do Django 3.x. django-distill
a partir da versão 1.7 suporta apenas Python 3. O suporte a Python 2 foi descartado. Se você precisar de suporte para Python 2, fixe django-distill
na versão 1.6 em seu requirements.txt ou Pipfile. Python 3.6 ou superior é recomendado.
django-distill
estende sites Django existentes com a capacidade de exportar sites estáticos totalmente funcionais. É adequado para sites como blogs que possuem um front-end principalmente estático, mas você ainda deseja usar um CMS para gerenciar o conteúdo.
django-distill
itera sobre URLs em seu projeto Django usando funções iteráveis fáceis de escrever para gerar os parâmetros para quaisquer páginas que você deseja salvar como HTML estático. Esses arquivos estáticos podem ser carregados automaticamente em um contêiner remoto estilo bucket, como Amazon S3, Googe Cloud Files, Microsoft Azure Storage ou gravados em um diretório local como uma versão estática local totalmente funcional do seu projeto. A geração de sites, ou processo de destilação, pode ser facilmente integrada aos fluxos de trabalho de CI/CD para implantar automaticamente sites estáticos no commit. django-distill
pode ser definido como uma extensão do Django para tornar os projetos Django compatíveis com a arquitetura de site estilo "Jamstack".
django-distill
se conecta diretamente ao framework Django existente sem a necessidade de escrever renderizadores customizados ou outro código mais detalhado. Você também pode integrar django-distill
com sites dinâmicos existentes e apenas gerar páginas estáticas para uma pequena subseção de páginas em vez de para o site inteiro.
Para arquivos estáticos em CDNs, você pode usar a seguinte biblioteca 'cache buster' para permitir atualizações rápidas de mídia estática ao enviar alterações:
? meeb/django-cachekiller
Existe um site de exemplo completo que cria um blog estático e usa django-distill
com django-cachekiller
via implantação contínua no Netlify disponível aqui:
? meeb/django-distill-exemplo
Instalar a partir do pip:
$ pip install django-distill
Adicione django_distill
ao seu INSTALLED_APPS
no seu settings.py
:
INSTALLED_APPS = [
# ... other apps here ...
'django_distill' ,
]
É isso.
django-distill
gera páginas estáticas e, portanto, apenas visualizações que permitem solicitações GET
que retornam um código de status HTTP 200
são suportadas.
Supõe-se que você esteja usando parâmetros de URI, como /blog/123-abc
, e não parâmetros de string de consulta, como /blog?post_id=123&title=abc
. Os parâmetros de string de consulta não fazem sentido para geração de páginas estáticas por motivos óbvios.
Arquivos de mídia estáticos, como imagens e folhas de estilo, são copiados do diretório de mídia estática definido em STATIC_ROOT
. Isso significa que você desejará executar ./manage.py collectstatic
antes de executar ./manage.py distill-local
se tiver feito alterações na mídia estática. django-distill
não encadeia esta solicitação por design, porém você pode habilitá-la com o argumento --collectstatic
.
Supondo que você tenha um projeto Django existente, edite um urls.py
para incluir a distill_path
que substitui a função path
padrão do Django e suporta os novos argumentos de palavras distill_func
distill_file
.
O distill_func
deve ser fornecido com uma função ou classe que pode ser chamada que retorne um iterável ou None
.
O argumento distill_file
é totalmente opcional e permite substituir o URL que de outra forma seria gerado a partir do reverso do regex do URL. Isso permite renomear URLs como /example
para qualquer outro nome, como example.html
. A partir da versão 0.8, qualquer URI que termine em barra /
será automaticamente modificado para terminar em /index.html
. Você pode usar parâmetros de string de formato no distill_file
para personalizar o nome do arquivo. Os valores de argumento do URL serão substituídos, por exemplo, {}
para argumentos posicionais ou {param_name}
para argumentos nomeados.
Um exemplo de configuração de destilação para um aplicativo de blog teórico seria:
# 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 ),
)
Seu site ainda funcionará de forma idêntica às alterações acima. Internamente, os parâmetros distill_func
e distill_file
são removidos e a URL é passada de volta ao Django para processamento normal. Isso não tem impacto no desempenho do tempo de execução, pois acontece apenas uma vez ao iniciar o aplicativo.
Se o seu caminho não tiver parâmetros URI, como /
ou /some-static-url
você não precisará especificar o parâmetro distill_func
se não desejar. Quanto aos caminhos sem parâmetros, distill_func
sempre retorna None
, este é definido como o comportamento padrão distill_func
s.
Você também pode usar a distill_re_path
, que substitui a função padrão django.urls.re_path
. Seu uso é idêntico ao acima:
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 ),
)
Se você estiver usando uma versão mais antiga do Django na série 1.x, você pode usar a distill_url
, que substitui as funções django.conf.urls.url
ou django.urls.url
. Seu uso é idêntico ao acima:
from django_distill import distill_url
urlpatterns = (
distill_url ( r'some/regex'
SomeView . as_view (),
name = 'url-view' ,
distill_func = some_func ),
)
Você também pode usar a formatação de string Python padrão distill_file
para permitir que você altere o caminho do arquivo de saída para um arquivo, se desejar. Observe que isso não atualiza a URL usada pelo Django, portanto, se você usar isso, certifique-se de que seu padrão path
corresponda ao padrão distill_file
ou seus links podem não funcionar no Django. Um exemplo:
# 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"
)
Todas as visualizações renderizadas pelo django-distill
em páginas estáticas devem retornar um código de status HTTP 200. Se por algum motivo você precisar renderizar uma visualização que não retorne um código de status HTTP 200, por exemplo, você também deseja gerar estaticamente uma página 404 que tenha uma visualização que (corretamente) retorne um código de status HTTP 404, você pode usar o distill_status_codes
argumento opcional para uma visão. Por exemplo:
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 ),
)
O argumento distill_status_codes
aceita uma tupla de códigos de status como números inteiros que são permitidos para a visualização retornar sem gerar um erro. Por padrão, isso é definido como (200,)
mas você pode substituí-lo se precisar para o seu site.
django-distill
irá espelhar qualquer versão instalada do Django que suporte, portanto em algum momento a distill_url
deixará de funcionar no futuro quando o próprio Django 2.x depreciar as funções django.conf.urls.url
e django.urls.url
. Você pode distill_re_path
como um substituto imediato. É aconselhável distill_path
distill_re_path
se você estiver construindo um novo site agora.
A internacionalização só é suportada para URLs, o conteúdo da página não pode ser traduzido dinamicamente. Por padrão, seu site será gerado usando o valor LANGUAGE_CODE
em seu settings.py
. Se você também definir settings.USE_I18N
como True
, defina outros códigos de idioma em seu valor settings.DISTILL_LANGUAGES
e registre URLs com i18n_patterns(...)
então seu site será gerado em vários idiomas. Isso pressupõe que seu site multilíngue funcione conforme o esperado antes de adicionar django-distill
.
Por exemplo, se você definir settings.LANGUAGE_CODE = 'en'
seu site será gerado em um idioma.
Se você tiver algo assim em seu settings.py
:
USE_I18N = True
DISTILL_LANGUAGES = [
'en' ,
'fr' ,
'de' ,
]
Ao mesmo tempo que usa i18n_patterns
em seu urls.py
assim:
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
)
)
Então suas visualizações serão geradas como /en/some-file.html
, /fr/some-file.html
e /de/some-file.html
. Esses URLs já devem funcionar (e ser traduzidos) pelo seu site. django-distill
não faz nenhuma mágica de tradução, apenas chama as URLs com o prefixo do código do idioma.
Nota Embora o método padrão sugerido seja usar settings.DISTILL_LANGUAGES
para manter as coisas separadas, django-distill
também verificará settings.LANGUAGES
para códigos de idioma.
Talvez seja necessário gerar uma lista de todas as URLs registradas com django-distill
. Por exemplo, você tem um blog gerado estaticamente com algumas centenas de páginas e deseja listar todos os URLs facilmente em um sitemap.xml
ou outra lista semelhante de todos os URLs. Você pode agrupar a visualização do mapa do site distill_path
e replicar toda a lógica de geração de URL importando suas visualizações distill_func
s do seu urls.py
e gerando tudo isso manualmente, mas como isso é um grande incômodo, há um auxiliar integrado para gerar todos os seus URLs que serão destilados para você.
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
Observe que distilled_urls()
retornará URLs apenas depois que todos os seus URLs em urls.py
tiverem sido carregados distill_path(...)
.
distill-local
Depois de agrupar os URLs que deseja gerar estaticamente, agora você pode gerar um site estático totalmente funcional com:
$ ./manage.py distill-local [optional /path/to/export/directory]
Nos bastidores, isso simplesmente itera todos os URLs registrados distill_url
e gera as páginas para eles usando partes da estrutura de testes do Django para falsificar solicitações. Depois que as páginas do site forem renderizadas, os arquivos de STATIC_ROOT
serão copiados. Os arquivos existentes com o mesmo nome são substituídos no diretório de destino e os arquivos órfãos são excluídos.
distill-local
suporta os seguintes argumentos opcionais:
--collectstatic
: Execute automaticamente collectstatic
em seu site antes da renderização, este é apenas um atalho para evitar que você digite um comando extra.
--quiet
: Desativa todas as saídas, exceto perguntas de confirmação.
--force
: assume 'sim' para todas as perguntas de confirmação.
--exclude-staticfiles
: Não copie nenhum arquivo estático, apenas renderize a saída das visualizações do Django.
--parallel-render [number of threads]
: Renderiza arquivos em paralelo em vários threads, isso pode acelerar a renderização. O padrão é 1
thread.
--generate-redirects
: tentativa de gerar redirecionamentos estáticos armazenados no aplicativo django.contrib.redirects
. Se você tiver um redirecionamento de /old/
para /new/
usar este sinalizador criará um redirecionamento de estilo HTML estático <meta http-equiv="refresh" content="...">
em /old/index.html
para /new/
.
Nota Se alguma de suas visualizações contiver um erro Python, a renderização falhará, o rastreamento de pilha será impresso no terminal e o comando de renderização será encerrado com um código de status 1.
distill-publish
$ ./manage.py distill-publish [optional destination here]
Se você configurou pelo menos um destino de publicação (veja abaixo), poderá usar o comando distill-publish
para publicar o site em um local remoto.
Isto realizará uma sincronização completa, removendo quaisquer arquivos remotos que não estejam mais presentes no site estático gerado e carregando quaisquer arquivos novos ou alterados. O site será construído em um diretório temporário localmente primeiro durante a publicação, que será excluído assim que o site for publicado. Cada arquivo será verificado se foi publicado corretamente, solicitando-o através do PUBLIC_URL
.
distill-publish
suporta os seguintes argumentos opcionais:
--collectstatic
: Execute automaticamente collectstatic
em seu site antes da renderização, este é apenas um atalho para evitar que você digite um comando extra.
--quiet
: Desativa todas as saídas, exceto perguntas de confirmação.
--force
: assume 'sim' para todas as perguntas de confirmação.
--exclude-staticfiles
: Não copie nenhum arquivo estático, apenas renderize a saída das visualizações do Django.
--skip-verify
: Não testa se os arquivos foram carregados corretamente no servidor.
--ignore-remote-content
: Não busca a lista de arquivos remotos. Isso significa que todos os arquivos serão carregados e nenhum arquivo remoto existente será excluído. Isso pode ser útil se você tiver muitos arquivos no servidor remoto e souber que deseja atualizar a maioria deles e não se importar se arquivos antigos permanecerem no servidor.
--parallel-publish [number of threads]
: Publique arquivos em paralelo em vários threads, isso pode acelerar a publicação. O padrão é 1
thread.
--parallel-render [number of threads]
: Renderiza arquivos em paralelo em vários threads, isso pode acelerar a renderização. O padrão é 1
thread.
--generate-redirects
: tentativa de gerar redirecionamentos estáticos armazenados no aplicativo django.contrib.redirects
. Se você tiver um redirecionamento de /old/
para /new/
usar este sinalizador criará um redirecionamento de estilo HTML estático <meta http-equiv="refresh" content="...">
em /old/index.html
para /new/
.
Observe que isso significa que se você usar --force
e --quiet
que o diretório de saída terá todos os arquivos que não fazem parte da exportação do site excluídos sem qualquer confirmação.
Nota Se alguma de suas visualizações contiver um erro Python, a renderização falhará, o rastreamento de pilha será impresso no terminal e o comando de renderização será encerrado com um código de status 1.
distill-test-publish
$ ./manage.py distill-test-publish [optional destination here]
Isso irá se conectar ao seu destino de publicação, autenticar-se nele, fazer upload de um arquivo com nome aleatório, verificar se ele existe em PUBLIC_URL
e excluí-lo novamente. Use isto para verificar se suas configurações de publicação estão corretas.
distill-test-publish
não tem argumentos.
Você pode definir as seguintes variáveis opcionais settings.py
:
DISTILL_DIR : string, diretório padrão para exportar:
DISTILL_DIR = '/path/to/export/directory'
DISTILL_PUBLISH : dicionário, como o settings.DATABASES
do Django, suporta default
:
DISTILL_PUBLISH = {
'default' : {
... options ...
},
'some-other-target' : {
... options ...
},
}
DISTILL_SKIP_ADMIN_DIRS : bool, o padrão é True
DISTILL_SKIP_ADMIN_DIRS = True
Defina DISTILL_SKIP_ADMIN_DIRS
como False
se você quiser que django-distill
também copie arquivos estáticos no diretório static/admin
. Normalmente, estes não são obrigatórios ou desejados para sites gerados estaticamente. O comportamento padrão é ignorar arquivos administrativos estáticos.
DISTILL_SKIP_STATICFILES_DIRS : lista, o padrão é []
DISTILL_SKIP_STATICFILES_DIRS = [ 'some_dir' ]
Defina DISTILL_SKIP_STATICFILES_DIRS
para uma lista de nomes de diretórios que você deseja que django-distill
ignore os diretórios em seu diretório static/
definido. Você pode usar isso para ignorar a cópia de diretórios contendo arquivos de aplicativos que você não está usando e que são agrupados em seu static/
diretório por collect-static
. Por exemplo, se você definir DISTILL_SKIP_STATICFILES_DIRS
como ['some_dir']
o diretório de arquivos estáticos static/some_dir
será ignorado.
DISTILL_LANGUAGES : lista, o padrão é []
DISTILL_LANGUAGES = [
'en' ,
'fr' ,
'de' ,
]
Defina DISTILL_LANGUAGES
como uma lista de códigos de idioma para tentar renderizar URLs. Consulte a seção “Internacionalização” para mais detalhes.
Se você estiver usando um ambiente de desenvolvimento local com suporte a HTTPS, pode ser necessário adicionar SECURE_SSL_REDIRECT = False
ao seu settings.py
para evitar que um CommandError
seja gerado quando uma solicitação retornar um redirecionamento 301 em vez do código de resposta HTTP/200 esperado.
A partir do django-distill
versão 3.0.0
você pode usar o método django_distill.renderer.render_single_file
para gravar um único arquivo no disco usando django_distill
. Isso é útil para gravar arquivos únicos no disco, por exemplo, você tem um site Django que possui alguns arquivos estáticos em um diretório escrito por django_distill
mas o resto do site é um site Django dinâmico normal. Você pode atualizar um arquivo HTML estático sempre que uma instância de modelo for salva. Você pode usar a gravação de arquivo único com sinais para conseguir isso. Por exemplo:
# 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
)
A sintaxe para render_single_file
é semelhante à url.reverse
do Django. A interface de uso completa é:
render_single_file (
'/path/to/output/directory' ,
'view-name-set-in-urls-py' ,
* view_args ,
** view_kwargs
)
Por exemplo, se você tivesse um URL de postagem de blog definido como:
# in urls.py
distill_path ( 'post/<int:blog_id>_<slug:blog_slug>.html' ,
PostView . as_view (),
name = 'blog-post' ,
distill_func = get_all_blogposts ),
Seu uso seria:
render_single_file (
'/path/to/output/directory' ,
'blog-post' ,
blog_id = 123 ,
blog_slug = 'blog-title-slug' ,
)
que escreveria o conteúdo de /post/123_blog-title-slug.html
em /path/to/output/directory
como o arquivo /path/to/output/directory/post/123_blog-title-slug.html
. Observe que quaisquer subdiretórios necessários ( /path/to/output/directory/post
neste exemplo) serão criados automaticamente se ainda não existirem. Todas as regras django-distill
se aplicam, como URLs que terminam em /
serão salvas como /index.html
para fazer sentido para um arquivo físico no disco.
Observe também que render_single_file
só pode ser importado e usado em um projeto Django inicializado.
Você pode publicar sites automaticamente em vários destinos remotos suportados por meio de backends, assim como você pode usar MySQL, SQLite, PostgreSQL etc. com Django, alterando o mecanismo de banco de dados backend. Atualmente os motores suportados pelo django-distill
são:
django_distill.backends.amazon_s3 : publique em um bucket do Amazon S3. Requer a biblioteca Python boto3
( $ pip install django-distill[amazon]
). O bucket já deve existir (use o painel de controle da AWS). Opções:
'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 : publique em um intervalo do Google Cloud Storage. Requer as bibliotecas Python google-api-python-client
e google-cloud-storage
( $ pip install django-distill[google]
). O bucket já deve existir e estar configurado para hospedar um site público estático (use o painel de controle do Google Cloud). Opções:
'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' ,
},
Observe que JSON_CREDENTIALS
é opcional; se não for especificado, as bibliotecas do Google tentarão outros métodos de autenticação, na ordem de pesquisa descrita aqui: https://cloud.google.com/docs/authentication/application-default-credentials (por exemplo, a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS
, serviço anexado conta, etc.).
django_distill.backends.microsoft_azure_storage : Publique em um contêiner do Microsoft Azure Blob Storage. Requer a biblioteca Python azure-storage-blob
( $ pip install django-distill[microsoft]
). A conta de armazenamento já deve existir e estar configurada para hospedar um site público estático (use o painel de controle do Microsoft Azure). Opções:
'some-microsoft-storage-account' : {
'ENGINE' : 'django_distill.backends.microsoft_azure_storage' ,
'PUBLIC_URL' : 'https://[storage-account-name]...windows.net/' ,
'CONNECTION_STRING' : '...' ,
},
Observe que cada conta de armazenamento do Azure oferece suporte a um site estático usando o contêiner mágico $web
, que é onde django-distill
tentará publicar seu site.
Existe um conjunto de testes mínimo, você pode executá-lo fechando este repositório, instalando as dependências necessárias em requirements.txt
e executando:
# ./run-tests.py
Todas as solicitações, problemas e comentários devidamente formatados e sensatos são bem-vindos.