Os 10 principais erros que os desenvolvedores do Django cometem
Publicados: 2022-03-11Neste tutorial, veremos alguns erros comuns que são frequentemente cometidos pelos desenvolvedores do Django e maneiras de evitá-los. Este tutorial é útil mesmo se você for um desenvolvedor habilidoso do Django porque erros, como manter configurações grandes demais ou conflitos de nomenclatura em ativos estáticos, não se limitam apenas a novos desenvolvedores dando sua primeira tentativa no Django.
O Django é um framework web Python gratuito e de código aberto que resolve de maneira útil os desafios comuns de desenvolvimento e permite que você crie aplicativos flexíveis e bem estruturados. O Django tem muitos recursos modernos prontos para uso. Para mim, pessoalmente, os recursos Admin, Object Relational Mapping tool (ORM), Routing e Templating fizeram do Django minha primeira escolha porque os aplicativos exigem muito trabalho e, embora eu goste do meu trabalho tanto quanto qualquer desenvolvedor, quero gastar o mínimo de tempo possível nessas tarefas repetitivas básicas. O Django permite que você faça tudo isso sem comprometer a flexibilidade.
O recurso matador do Django é uma poderosa interface de administração configurável que é construída automaticamente (automagicamente?) a partir do esquema de seus modelos e dos modelos do painel de administração, fazendo você se sentir como um assistente. Por meio da interface Admin, um usuário pode configurar muitas coisas, incluindo a lista de controle de acesso (ACL), permissões e ações em nível de linha, filtros, pedidos, widgets, formulários, auxiliares de URL extras e qualquer outra coisa que você possa imaginar. Acredito que todo aplicativo requer um painel de administração - se ainda não, é simplesmente uma questão de tempo até que seu aplicativo básico precise de um. Com o Django admin, você pode criar um de forma rápida e flexível.
O Django tem um ORM poderoso que funciona com todos os principais bancos de dados prontos para uso. Como é preguiçoso, ele acessa seu banco de dados apenas quando você precisa, ao contrário de outros ORMs. Ele suporta todas as principais instruções SQL (e funções) que você pode usar em seu código-fonte Python e se sente muito confortável por causa dos recursos do Python.
O mecanismo de modelagem do Django é muito flexível e poderoso ao mesmo tempo. Você pode usar muitos filtros e tags padrão, bem como criar seus novos filtros e tags personalizados para seu projeto. O Django suporta outros mecanismos de modelo, bem como modelos Django, e fornece uma API para fácil integração de outros mecanismos de modelo por meio de funções de atalho padrão para processamento de modelos.
O Django tem muitos outros grandes recursos, como um roteador de URL que pode analisar solicitações recebidas e criar novas URLs a partir de um esquema de roteador. Como um todo, o framework Django é uma experiência agradável e sempre que precisar de ajuda, basta ler a documentação.
Erro nº 1: usando o ambiente Python do sistema global para dependências do projeto
Não use o ambiente global do Python para dependências do projeto, pois isso pode gerar conflitos de dependência. O Python não pode usar várias versões de pacote ao mesmo tempo. Isso pode ser um problema se projetos diferentes exigirem diferentes versões incompatíveis do mesmo pacote.
Esse erro geralmente é cometido por novos desenvolvedores Python e Django que não conhecem os recursos de isolamento de ambiente do Python.
Existem várias maneiras de isolar seu ambiente, mas as formas mais comuns são:
- virtualenv: Um pacote Python que gera uma pasta de ambiente Python e possui scripts para [des]ativar o ambiente e gerenciar pacotes Python instalados no ambiente. Este é o meu método favorito porque é a maneira mais simples de fazer o trabalho. Normalmente, crio o ambiente próximo à pasta do projeto.
- virtualenvwrapper: Um pacote Python que é instalado globalmente e fornece um conjunto de ferramentas para criar/excluir/ativar/etc. ambientes virtuais. Todos os ambientes virtuais são armazenados em uma pasta (que pode ser substituída por meio da variável de ambiente WORKON_HOME). Não vejo vantagens em usar
virtualenvwrapper
em vez devirtualenv
. - Máquinas Virtuais (VM): Não há maior isolamento do que uma máquina virtual inteira dedicada ao seu aplicativo. Existem muitas ferramentas para escolher, incluindo VirtualBox (gratuito), VMware, Parallels e Proxmox (meu favorito pessoal, e tem uma versão gratuita). Combinado com uma ferramenta de automação de VM como o Vagrant, esta pode ser uma solução extremamente poderosa.
- Containers: Nos últimos anos, tenho usado o Docker em quase todos os projetos, especialmente em todos os novos projetos que começo do zero. O Docker é uma ferramenta incrível que fornece muitos recursos e possui muitas ferramentas de terceiros para automação de contêineres. Ele possui um recurso de cache de camada que torna a reconstrução de seus contêineres extremamente rápida. Em containers, uso o ambiente global do sistema Python, pois cada container possui seu próprio sistema de arquivos e os projetos são isolados em alto nível. O Docker permite que novos membros da equipe comecem a trabalhar no projeto mais rapidamente, especialmente se tiverem experiência com o Docker.
Se você me perguntar, prefiro o pacote virtualenv
Python e os contêineres Docker para isolamento e gerenciamento de dependências do projeto.
Erro nº 2: não fixar dependências do projeto em um arquivo requirements.txt
Todo novo projeto Python deve começar com um arquivo requirements.txt e um novo ambiente isolado. Normalmente você instala todos os pacotes através do pip/easy_install
, mas nunca se esqueça de adicioná-los ao seu arquivo requirements.txt
também. Isso torna mais fácil ( possível ser mais apropriado) implantar seu projeto em servidores ou para um membro da equipe inicializar o projeto em sua própria máquina.
Além disso, é igualmente importante fixar a versão específica de suas dependências no arquivo requirements.txt
. Normalmente, diferentes versões de um pacote fornecem diferentes módulos, funções e parâmetros de função; mesmo uma pequena mudança de versão em uma dependência pode quebrar seu pacote. Este é um problema muito sério se o seu projeto estiver ativo e você tiver implantações agendadas regularmente, pois, sem controle de versão, seu sistema de compilação sempre instalará a versão mais recente disponível do pacote.
Sempre fixe seus pacotes para produção! Pessoalmente, eu uso uma ferramenta muito boa chamada pip-tools que me ajuda a fazer isso. Ele fornece um conjunto de ferramentas de linha de comando que ajudam a gerenciar suas dependências. Ele gera automaticamente um requirements.txt
que fixa não apenas suas dependências, mas toda a sua árvore de dependências, que inclui as dependências de suas dependências.
Às vezes, você deseja atualizar apenas alguns pacotes da sua lista de dependências (por exemplo, apenas Django/Flask/qualquer framework ou utilitário), se você usou “pip freeze” você não sabe quais dependências são para quais pacotes, e então você não pode atualizar uma dependência. Com o pip-tools, no entanto, ele fixa automaticamente os pacotes dependendo de qual dependência você fixou, então ele resolve automaticamente quais pacotes precisam ser atualizados. Como bônus, você também sabe exatamente qual pacote veio de qual dependência por causa de como ele os marca com comentários no arquivo requirements.txt
.
Para ser mais cauteloso, é uma boa ideia fazer backup de seus arquivos de origem de dependência também! Mantenha uma cópia em seu sistema de arquivos, uma pasta gerenciada pelo Git, pasta S3, FTP, SFTP — em qualquer lugar, mas tenha-a à mão. Houve casos em que um pacote relativamente pequeno não listado quebrou um grande número de pacotes no npm. Pip fornece a ferramenta para baixar todas as dependências necessárias como arquivos de origem, leia mais executando pip help download
.
Erro nº 3: usando funções Python antigas em vez de exibições baseadas em classes
Às vezes, é uma boa ideia usar uma pequena função Python no arquivo views.py
de um aplicativo especialmente para testes ou visualizações de utilitários, mas geralmente você deve usar visualizações baseadas em classes (CBVs) em seus aplicativos.
CBVs são visões genéricas que fornecem classes abstratas implementando tarefas comuns de desenvolvimento web criadas por profissionais e cobrindo todos os comportamentos comuns. Eles têm uma API estruturada incrível e você pode usar todas as vantagens da programação orientada a objetos ao usar CBVs. Isso torna seu código-fonte mais claro e legível. Esqueça a dor de usar as funções de visualização padrão do Django para listagens, operações CRUD, processamento de formulários, etc. faz espaguete do seu código-fonte no caso de usar funções de visualização em vez de CBVs) que configuram o comportamento da visualização.
Por exemplo, você pode ter diferentes mix-ins em seu projeto que substituem comportamentos básicos de CBV para criar contextos de exibição, verificar autorização no nível de linha, criar caminhos de modelo automaticamente da estrutura do aplicativo, integrar cache inteligente e muito mais.
Eu construí o pacote chamado Django Template Names, que padroniza os nomes dos templates para suas visualizações com base em um nome de aplicativo e um nome de classe de visualização. Eu o uso todos os dias e economiza muito do meu tempo para inventar nomes. Basta colocar o mixin em seu CBV — class Detail(TemplateNames, DetailView):
— e ele começará a funcionar! Claro, você pode substituir minhas funções e adicionar modelos responsivos para dispositivos móveis, modelos diferentes para agentes de usuário ou qualquer outra coisa que desejar.
Erro No. 4: Escrevendo Vistas Gordas e Modelos Magros
Escrever a lógica do seu aplicativo em visualizações em vez de modelos significa que você escreveu o código que pertence ao seu modelo na visualização, tornando-o “gordo” e seu modelo “magro”.
Você deveria escrever modelos gordos, vistas magras.
Divida a lógica em pequenos métodos em seus modelos. Isso permite que você o use várias vezes de várias fontes (IU da interface de administração, interface do usuário de front-end, pontos de extremidade da API, várias visualizações) em algumas linhas de código, em vez de copiar e colar toneladas de código. Então, da próxima vez que você enviar um e-mail para um usuário, estenda o modelo com uma função de e-mail em vez de escrever essa lógica em seu controlador.
Isso também facilita o teste de unidade do seu código porque você pode testar a lógica de e-mail em um só lugar, em vez de repetidamente em todos os controladores em que isso ocorre.
Você pode ler mais sobre o problema no projeto Django Best Practices. A solução é simples: Escreva modelos gordos e visualizações magras, então vamos fazer isso em seu próximo projeto (ou refatorar seu atual).
Erro nº 5: um arquivo de configurações enorme e incontrolável
Até mesmo o novo arquivo de configurações do projeto Django tem muitas configurações. Em um projeto real, um arquivo de configurações cresce para mais de 700 linhas de configuração e se tornará difícil de manter, especialmente quando seus ambientes de desenvolvimento, produção e preparação precisam de configurações personalizadas.
Você pode dividir o arquivo de configuração manualmente e criar carregadores personalizados, mas quero apresentá-lo a um bom e bem testado pacote Python, Django Split Settings, que eu co-autor.

O pacote fornece duas funções— optional
e include
que suportam curingas para os caminhos e importam seus arquivos de configuração no mesmo contexto, simplificando a construção de sua configuração usando entradas de configuração declaradas em arquivos carregados anteriormente. Ele não afeta o desempenho do Django e você pode usá-lo em qualquer projeto.
Confira o exemplo de configuração mínima:
from split_settings.tools import optional, include include( 'components/base.py', 'components/database.py', 'components/*.py', # the project different envs settings optional('envs/devel/*.py'), optional('envs/production/*.py'), optional('envs/staging/*.py'), # for any local settings optional('local_settings.py'), )
Erro nº 6: aplicativo tudo-em-um, estrutura de aplicativo ruim e posicionamento incorreto de recursos
Qualquer projeto Django consiste em vários aplicativos. Na notação Django, um aplicativo é um pacote Python que contém pelo menos arquivos __init__.py
e models.py
; nas versões mais recentes do Django, models.py
não é mais necessário. __init__.py
é suficiente.
Os aplicativos Django podem conter módulos Python, módulos específicos do Django (views, URLs, models, admin, forms, template tags, etc), arquivos estáticos, templates, migrações de banco de dados, comandos de gerenciamento, testes de unidade e muito mais. Você deve dividir seus aplicativos monolíticos em aplicativos pequenos e reutilizáveis usando lógica simples. Você deve ser capaz de descrever todo o propósito do aplicativo em uma ou duas frases curtas. Por exemplo: “Permite que os usuários se registrem e ativem sua conta por e-mail”.
É uma boa ideia chamar a pasta do projeto project
e colocar os aplicativos em project/apps/
. Em seguida, coloque todas as dependências do aplicativo em suas próprias subpastas.
Exemplos:
- Arquivos estáticos:
project/apps/appname/static/appname/
- Tags de modelo:
project/apps/appname/templatetags/appname.py
- Arquivos de modelo:
project/apps/appname/templates/appname/
Sempre prefixe o nome do aplicativo nas subpastas porque todas as pastas estáticas são mescladas em uma pasta e, se dois ou mais aplicativos tiverem um arquivo js/core.js
, o último aplicativo em settings.INSTALLED_APPLICATIONS
substituirá os anteriores. Certa vez, tive esse bug no meu projeto atual e perdi cerca de seis horas depurando até perceber que outro desenvolvedor havia substituído static/admin/js/core.js
porque a equipe estava implementando um painel de administração SPA personalizado e nomeava seus arquivos da mesma maneira.
Aqui está uma estrutura de exemplo para um aplicativo de portal que possui muitos recursos e módulos Python.
root@c5b96c395cfb:/test# tree project/apps/portal/ project/apps/portal/ ├── __init__.py ├── admin.py ├── apps.py ├── management │ ├── __init__.py │ └── commands │ ├── __init__.py │ └── update_portal_feeds.py ├── migrations │ └── __init__.py ├── models.py ├── static │ └── portal │ ├── css │ ├── img │ └── js ├── templates │ └── portal │ └── index.html ├── templatetags │ ├── __init__.py │ └── portal.py ├── tests.py ├── urls.py └── views.py 11 directories, 14 files
Usando essa estrutura, você pode a qualquer momento exportar o aplicativo para outro pacote Python e usá-lo novamente. Você pode até publicá-lo no PyPi como um pacote de código aberto ou movê-lo para outra pasta.
Você terminará com uma estrutura de projeto como esta:
root@c5b96c395cfb:/test# tree -L 3 . ├── deploy │ ├── chef │ └── docker │ ├── devel │ └── production ├── docs ├── logs ├── manage.py ├── media ├── project │ ├── __init__.py │ ├── apps │ │ ├── auth │ │ ├── blog │ │ ├── faq │ │ ├── pages │ │ ├── portal │ │ └── users │ ├── conf │ ├── settings.py │ ├── static │ ├── templates │ ├── urls.py │ └── wsgi.py └── static └── admin ├── css ├── fonts ├── img └── js 25 directories, 5 files
Em um projeto real, é claro, será mais complexo, mas essa estrutura torna as coisas mais simples e limpas.
Erro nº 7: STATICFILES_DIRS
e STATIC_ROOT
confundem desenvolvedores Django novatos
Arquivos estáticos são ativos que não mudam com o uso do aplicativo, por exemplo, JavaScript, CSS, imagens, fontes, etc. No Django, eles são apenas “coletados” em um diretório público durante o processo de implantação.
No modo de desenvolvimento python manage.py runserver
— o Django procura por arquivos estáticos usando a configuração STATICFILES_FINDERS
. Por padrão, ele tenta localizar o arquivo estático solicitado nas pastas listadas na configuração STATICFILES_DIRS
. Em caso de falha, o Django tenta encontrar o arquivo usando django.contrib.staticfiles.finders.AppDirectoriesFinder
, que procura na pasta static
de cada aplicativo instalado no projeto. Isso permite escrever aplicativos reutilizáveis que são enviados com seus próprios arquivos estáticos.
Na produção, você serve sua estática usando um servidor web autônomo como o Nginx. O servidor web não sabe nada sobre a estrutura de aplicativos do projeto Django ou em quais pastas seus arquivos estáticos são distribuídos. Felizmente, o Django fornece o comando collect static management python manage.py collectstatic
collectstatic , que percorre STATICFILES_FINDERS
e copia todos os arquivos estáticos de aplicativos static
pastas e pastas listadas em STATICFILES_DIRS
no diretório especificado na configuração STATIC_ROOT
. Isso permite a resolução de recursos de arquivos estáticos usando a mesma lógica do servidor de modo de desenvolvimento Django e tem todos os arquivos estáticos em um só lugar para seu servidor web.
Não se esqueça de executar o collectstatic
em seu ambiente de produção!
Erro nº 8: STATICFILES_STORAGE
padrão, carregadores de templates Django em produção
STATICFILES_STORAGE
Vamos falar sobre gerenciamento de ativos do ambiente de produção. Podemos fornecer a melhor experiência ao usuário se usarmos uma política de “ativos nunca expiram” (sobre a qual você pode ler mais aqui). Isso significa que todos os nossos arquivos estáticos devem ser armazenados em cache pelos navegadores da Web por semanas, meses ou até anos. Em outras palavras, seus usuários devem baixar seus ativos apenas uma vez!
Isso é legal, e podemos fazer isso com poucas linhas na configuração do Nginx para nossa pasta de arquivos estáticos, mas e a invalidação de cache? Se o usuário baixar nossos ativos apenas uma vez, o que acontecerá se você atualizar seu logotipo, fontes, JavaScript ou a cor do texto de um item em um menu? Para contornar isso, você deve gerar URLs e nomes de arquivos exclusivos para nossos arquivos estáticos em cada implantação!
Podemos fazer isso simplesmente usando ManifestStaticFilesStorage como STATICFILES_STORAGE
(cuidado, o hash só é habilitado no modo DEBUG=false
) e executando o comando de gerenciamento collectstatic
discutido acima. Isso diminuirá a contagem de solicitações de ativos para seu site de produção e fará com que seu site seja renderizado muito mais rápido.
Carregador de templates Django em cache
Outro recurso legal do Django é o carregador de templates em cache, que não recarrega e analisa arquivos de template em cada renderização de template. A análise de modelo é uma operação muito cara e usa muitos recursos. Por padrão, os templates do Django são analisados em cada solicitação, mas isso é ruim, especialmente durante a produção, onde você pode processar milhares de solicitações em um curto espaço de tempo.
Confira a seção de configuração cached.Loader
para um bom exemplo e detalhes sobre como fazer isso. Não use o carregador no modo de desenvolvimento porque ele não recarrega os modelos analisados do sistema de arquivos; você precisará reiniciar seu projeto usando python manage.py startapp
em cada alteração de modelo. Isso pode ser irritante durante o desenvolvimento, mas é perfeito para o ambiente de produção.
Erro nº 9: scripts Python puros para utilitários ou scripts
O Django fornece um recurso muito bom chamado Comandos de Gerenciamento. Basta usá-lo em vez de reinventar rodas e escrever scripts Python brutos para seus utilitários de projeto.
Além disso, confira o pacote Django Extensions, que é uma coleção de extensões personalizadas para o Django. Talvez alguém já tenha implementado seus comandos! Já existem muitos comandos de tarefas comuns.
Erro nº 10: Reinventando a roda
Django e Python têm milhares de soluções prontas para uso. Tente pesquisar no Google antes de escrever algo que não seja exclusivo; provavelmente já existe uma solução rica em recursos.
Apenas tente tornar as coisas simples. Google primeiro! Instale, configure, estenda e integre em seu projeto se você encontrar um pacote de boa qualidade e, claro, contribua com o código aberto quando tiver uma chance.
Para começar, aqui está uma lista dos meus próprios pacotes públicos para o Django:
- O URL de macros do Django facilita escrever (e ler) padrões de URL em seus aplicativos Django usando macros.
- Django Templates Names é um pequeno mix-in que permite padronizar facilmente seus nomes de templates CBV.
- django-split-settings permite que você organize as configurações do Django em vários arquivos e diretórios. Substitua e modifique facilmente as configurações. Use curingas nos caminhos do arquivo de configurações e marque os arquivos de configurações como opcionais.
Não se repita (SEC)!
Gosto muito da metodologia DRY; é por isso que eu criei o esqueleto do Django como uma ferramenta de conveniência que tem alguns recursos realmente legais prontos para uso:
- Imagens do Docker para desenvolvimento/produção, gerenciadas pelo docker-compose, que permite orquestrar facilmente uma lista de contêineres.
- Script de malha simples para implantação de produção.
- Configuração para o pacote Django Split Settings com configurações para fontes base e locais.
- Webpack integrado ao projeto - Somente a pasta
dist
será coletada pelo Django no comandocollectstatic
. - Definiu todas as configurações e recursos básicos do Django, como modelos Django que podem ser armazenados em cache em produção, arquivos estáticos com hash, barra de ferramentas de depuração integrada, registro, etc.
É um Django Skeleton pronto para usar para o seu próximo projeto a partir do zero e, esperançosamente, economizará muito tempo ao inicializar seu projeto. O Webpack possui configuração básica mínima, mas também possui SASS instalado pré-configurado para lidar com arquivos .scss
.