Destaques do Django: A modelagem salva as linhas (Parte 2)

Publicados: 2022-03-10
Resumo rápido ↬ A criação de código front-end no Django com modelagem e renderização do lado do servidor combina o controle refinado do HTML manuscrito com o código limpo e recursos poderosos das páginas geradas. Exploramos a divisão de uma página da Web complexa em vários modelos, compondo esses componentes e aplicando tags e filtros para refatorar uma página HTML simples.

Algumas abordagens sem frescuras para construir sites exigem que um desenvolvedor escreva cada linha de HTML à mão. No outro extremo, os construtores de sites comerciais sem código criam todo o HTML para o usuário automaticamente, muitas vezes às custas da legibilidade do código resultante. A modelagem está no meio desse espectro, mas mais próxima do HTML escrito à mão do que, digamos, gerar a estrutura da página em um aplicativo de página única usando o React ou uma biblioteca semelhante. Esse ponto ideal no continuum fornece muitos dos benefícios do HTML manual do zero (código semântico/legível, controle total sobre a estrutura da página, carregamentos rápidos de página) e adiciona separação de preocupações e concisão, tudo às custas de gastar algum tempo escrevendo HTML modificado manualmente. Este artigo demonstra o uso de templates Django para escrever páginas complexas.

Espectro HTML. (Visualização grande)

O tópico de hoje se aplica além do framework Django. Flask (outro framework web) e Pelican (um gerador de site estático) são apenas dois de muitos outros projetos Python que usam a mesma abordagem de modelagem. Jinja2 é o mecanismo de modelagem que todos os três frameworks usam, embora você possa usar um diferente alterando as configurações do projeto (estritamente falando, Jinja2 é um superconjunto de modelagem Django). É uma biblioteca independente que você pode incorporar em seus próprios projetos mesmo sem uma estrutura, portanto, as técnicas deste artigo são amplamente úteis.

Partes anteriores da série:

  • Destaques do Django: Modelos de usuário e autenticação (Parte 1)
  • Destaques do Django: modelos, administração e aproveitamento do banco de dados relacional (Parte 3)
  • Destaques do Django: disputando ativos estáticos e arquivos de mídia (Parte 4)
Mais depois do salto! Continue lendo abaixo ↓

Renderização do lado do servidor

Um modelo é apenas um arquivo HTML onde o HTML foi estendido com símbolos adicionais. Lembre-se do que HTML significa: H yper T ext Markup L aguage . Jinja2, nossa linguagem de modelagem, simplesmente adiciona à linguagem símbolos de marcação significativos adicionais. Essas estruturas adicionais são interpretadas quando o servidor renderiza o modelo para servir uma página HTML simples ao usuário (ou seja, os símbolos adicionais da linguagem de modelo não chegam à saída final).

A renderização do lado do servidor é o processo de construção de uma página da Web em resposta a uma solicitação. O Django usa renderização do lado do servidor para servir páginas HTML para o cliente. Ao final de sua execução, uma função de visualização combina a solicitação HTTP, um ou mais modelos e, opcionalmente, os dados acessados ​​durante a execução da função para construir uma única página HTML que ela envia como resposta ao cliente. Os dados vão do banco de dados, passam pela exibição e entram no modelo para chegar ao usuário. Não se preocupe se essa explicação abstrata não fizer muito sentido, vamos nos voltar para um exemplo concreto no restante deste artigo.

Configurando

Para nosso exemplo, pegaremos uma página da Web bastante complexa, o modelo de administração do Bootstrap, e reescreveremos o HTML como um modelo Jinja2. Observe que a biblioteca licenciada pelo MIT usa um sistema de modelagem diferente (baseado em JavaScript e Pug) para gerar a página que você vê, mas sua abordagem difere substancialmente da modelagem no estilo Jinja2, portanto, este exemplo é mais uma engenharia reversa do que uma tradução de seu excelente projeto de código aberto. Para ver a página que estaremos construindo, você pode dar uma olhada na visualização ao vivo do Start Bootstrap.

Eu preparei um aplicativo de exemplo para este artigo. Para executar o projeto Django em seu próprio computador, inicie seu ambiente virtual Python 3 e execute os seguintes comandos:

 pip install django git clone https://github.com/philipkiely/sm_dh_2_dashboard.git cd sm_dh_2_dashboard python manage.py migrate python manage.py createsuperuser python manage.py loaddata employee_fixture.json python manage.py runserver

Em seguida, abra seu navegador da Web e navegue até https://127.0.0.1:8000 . Você deverá ver a mesma página da visualização, correspondendo à imagem abaixo.

Página principal do painel. (Visualização grande)

Como este tutorial é focado no frontend, o aplicativo Django subjacente é muito simples. Isso pode parecer muita configuração para apresentar uma única página da Web e, para ser justo, é. No entanto, essa configuração também pode suportar um aplicativo muito mais robusto.

Agora, estamos prontos para percorrer o processo de transformar este arquivo HTML de 668 linhas em um site Django devidamente arquitetado.

Modelos e herança

O primeiro passo para refatorar centenas de linhas de HTML em código limpo é dividir os elementos em seus próprios templates, que o Django irá compor em uma única página web durante a etapa de renderização.

Dê uma olhada em páginas/modelos . Você deve ver cinco arquivos:

  • base.html , o modelo base que cada página da Web estenderá. Ele contém o <head> com o título, importações de CSS, etc.
  • navbar.html , o HTML da barra de navegação superior, um componente a ser incluído quando necessário.
  • footer.html , o código para o rodapé da página, outro componente a ser incluído quando necessário.
  • sidebar.html , o HTML para a barra lateral, um terceiro componente a ser incluído quando necessário.
  • index.html , o código exclusivo da página principal. Este modelo estende o modelo base e inclui os três componentes.

O Django monta esses cinco arquivos como Voltron para renderizar a página de índice. As palavras-chave que permitem isso são {% block %} , {% include %} e {% extend %} . Em base.html :

 {% block content %} {% endblock %}

Essas duas linhas deixam espaço para outros templates que estendem base.html para inserir seu próprio HTML. Observe que o content é um nome de variável, você pode ter vários blocos com nomes diferentes em um template, dando flexibilidade aos templates filhos. Vemos como estender isso em index.html :

 {% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}

O uso da palavra-chave extends com o nome do modelo base dá à página de índice sua estrutura, evitando que copiemos no cabeçalho (observe que o nome do arquivo é um caminho relativo na forma de string entre aspas duplas). A página de índice inclui todos os três componentes comuns à maioria das páginas do site. Trazemos esses componentes com tags de include conforme abaixo:

 {% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}

No geral, essa estrutura oferece três benefícios principais em relação à escrita de páginas individualmente:

  • Código DRY (não se repita)
    Ao fatorar o código comum em arquivos específicos, podemos alterar o código em apenas um local e refletir essas alterações em todas as páginas.
  • Maior legibilidade
    Em vez de percorrer um arquivo gigante, você pode isolar o componente específico em que está interessado.
  • Separação de preocupações
    O código para, digamos, a barra lateral agora tem que estar em um só lugar, não pode haver nenhuma tag de script desonesta flutuando na parte inferior do código ou outra mistura entre o que deveria ser componentes separados. A fatoração de peças individuais força essa boa prática de codificação.

Embora pudéssemos economizar ainda mais linhas de código colocando os componentes específicos no modelo base.html , mantê-los separados oferece duas vantagens. A primeira é que podemos incorporá-los exatamente onde eles pertencem em um único bloco (isso é relevante apenas para o footer.html que vai dentro da div principal do bloco de content ). A outra vantagem é que se fôssemos criar uma página, digamos uma página de erro 404, e não quiséssemos a barra lateral ou o rodapé, poderíamos deixá-los de fora.

Esses recursos são parciais para o curso de modelagem. Agora, nos voltamos para tags poderosas que podemos usar em nosso index.html para fornecer recursos dinâmicos e salvar centenas de linhas de código.

Duas Tags Fundamentais

Isso está muito longe de ser uma lista exaustiva de tags disponíveis. A documentação do Django sobre modelagem fornece essa enumeração. Por enquanto, estamos nos concentrando nos casos de uso de dois dos elementos mais comuns da linguagem de modelagem. Em meu próprio trabalho, basicamente só uso a tag for e if regularmente, embora a dúzia ou mais de outras tags fornecidas tenham seus próprios casos de uso, que recomendo que você revise na referência do modelo.

Antes de chegarmos às tags, quero fazer uma observação sobre a sintaxe. A tag {% foo %} significa que “foo” é uma função ou outro recurso do próprio sistema de templates, enquanto a tag {{ bar }} significa que “bar” é uma variável passada para o template específico.

Para loops

No index.html restante, a maior seção de código por várias centenas de linhas é a tabela. Em vez dessa tabela codificada, podemos gerar a tabela dinamicamente a partir do banco de dados. Lembre-se de python manage.py loaddata employee_fixture.json da etapa de configuração. Esse comando usou um arquivo JSON, chamado Django Fixture, para carregar todos os 57 registros de funcionários no banco de dados do aplicativo. Usamos a view em views.py para passar esses dados para o template:

 from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})

O terceiro argumento posicional a ser render é um dicionário de dados que é disponibilizado para o modelo. Usamos esses dados e a tag for para construir a tabela. Mesmo no modelo original do qual adaptei esta página, a tabela de funcionários estava codificada. Nossa nova abordagem corta centenas de linhas de linhas de tabela codificadas e repetitivas. index.html agora contém:

 {% for employee in employees %} <trv <td>{{ employee.name }}</td> <td>{{ employee.position }}</td> <td>{{ employee.office }}</td> <td>{{ employee.age }}</td> vtd>{{ employee.start_date }}</td> <td>${{ employee.salary }}</td> </tr> {% endfor %}

A maior vantagem é que isso simplifica muito o processo de atualização da tabela. Em vez de um desenvolvedor editar manualmente o HTML para refletir um aumento de salário ou uma nova contratação e, em seguida, enviar essa alteração para produção, qualquer administrador pode usar o painel de administração para fazer atualizações em tempo real (https://127.0.0.1/admin, use as credenciais que você criou com python manage.py createsuperuser para acessar). Este é um benefício de usar o Django com esse mecanismo de renderização em vez de usá-lo sozinho em um gerador de site estático ou outra abordagem de modelagem.

Se mais

A tag if é uma tag incrivelmente poderosa que permite avaliar expressões dentro do modelo e ajustar o HTML de acordo. Linhas como {% if 1 == 2 %} são perfeitamente válidas, ainda que um pouco inúteis, pois avaliam sempre o mesmo resultado. Onde a tag if brilha é ao interagir com os dados passados ​​para o modelo pela visualização. Considere o seguinte exemplo de sidebar.html :

 <div class="sb-sidenav-footer"> <div class="small"> Logged in as: </div> {% if user.is_authenticated %} {{ user.username }} {% else %} Start Bootstrap {% endif %} </div>

Observe que todo o objeto de usuário é passado para o modelo por padrão, sem especificarmos nada na visualização para que isso aconteça. Isso nos permite acessar o status de autenticação do usuário (ou a falta dele), nome de usuário e outros recursos, incluindo os seguintes relacionamentos de chave estrangeira para acessar dados armazenados em um perfil de usuário ou outro modelo conectado, tudo a partir do arquivo HTML.

Você pode estar preocupado que esse nível de acesso possa representar riscos de segurança. No entanto, lembre-se de que esses modelos são para uma estrutura de renderização do lado do servidor. Depois de construir a página, as tags se consumiram e são substituídas por HTML puro. Assim, se uma instrução if introduzir dados em uma página sob algumas condições, mas os dados não forem usados ​​em uma determinada instância, esses dados não serão enviados ao cliente, pois a instrução if é avaliada no lado do servidor. Isso significa que um modelo construído adequadamente é um método muito seguro de adicionar dados confidenciais a páginas sem que esses dados saiam do servidor, a menos que seja necessário. Dito isso, o uso de templates Django não elimina a necessidade de comunicar informações confidenciais de maneira segura e criptografada, significa simplesmente que verificações de segurança como user.is_authenticated podem acontecer com segurança no HTML, pois ele é processado no lado do servidor.

Esse recurso tem vários outros casos de uso. Por exemplo, em uma página inicial de um produto geral, você pode ocultar os botões "inscrever-se" e "entrar" e substituí-los por um botão "sair" para usuários conectados. Outro uso comum é mostrar e ocultar mensagens de sucesso ou erro para operações como envio de formulários. Observe que geralmente você não ocultaria a página inteira se o usuário não estivesse logado. Uma maneira melhor de alterar a página inteira com base no status de autenticação do usuário é tratá-la na função apropriada em views.py .

Filtrando

Parte do trabalho da visualização é formatar os dados adequadamente para a página. Para isso, temos uma poderosa extensão para tags: filtros. Existem muitos filtros disponíveis no Django para realizar ações como justificar texto, formatar datas e adicionar números. Basicamente, você pode pensar em um filtro como uma função que é aplicada à variável em uma tag. Por exemplo, queremos que nossos números de salário sejam “$ 1.200.000” em vez de “1200000”. Usaremos um filtro para fazer o trabalho em index.html :

 <td>${{ employee.salary|intcomma }}</td>

O caractere de tubo | é o filtro que aplica o comando intcomma à variável employee.salary . O caractere “$” não vem do template, para um elemento como aquele que aparece toda vez, é mais fácil apenas colocá-lo fora da tag.

Observe que intcomma exige que incluamos {% load humanize %} no topo de nosso index.html e 'django.contrib.humanize', em nosso INSTALLED_APPS em settings.py . Isso é feito para você no aplicativo de amostra fornecido.

Conclusão

A renderização do lado do servidor com o mecanismo Jinja2 fornece ferramentas importantes para a criação de código front-end limpo, adaptável e responsivo. Separar páginas em arquivos permite componentes DRY com composição flexível. As tags fornecem recursos fundamentais para exibir dados passados ​​do banco de dados por funções de visualização. Feito corretamente, essa abordagem pode aumentar a velocidade, os recursos de SEO, a segurança e a usabilidade do site, e é um aspecto central da programação em Django e estruturas semelhantes.

Se você ainda não fez isso, confira o aplicativo de exemplo e tente adicionar suas próprias tags e filtros usando a lista completa.

Django Highlights é uma série que apresenta conceitos importantes de desenvolvimento web em Django. Cada artigo é escrito como um guia independente para uma faceta do desenvolvimento do Django destinada a ajudar desenvolvedores e designers de front-end a alcançar uma compreensão mais profunda da “outra metade” da base de código. Esses artigos são construídos principalmente para ajudá-lo a entender a teoria e a convenção, mas contêm alguns exemplos de código, que são escritos em Django 3.0.

Partes anteriores da série:

  • Destaques do Django: Modelos de usuário e autenticação (Parte 1)
  • Destaques do Django: modelos, administração e aproveitamento do banco de dados relacional (Parte 3)
  • Destaques do Django: disputando ativos estáticos e arquivos de mídia (Parte 4)