(Grande parte dessas dicas estão no livro Two Scoops of Django, como sugeriu nosso amigo Bernardo Gomes.)

Hoje a minha intenção é fazer algo um pouco mais técnico. Grande parte dos meus amigos leitores são programadores. Destes, grande parte programam em Python e usam Django para suas aplicações web. Pensando nisso, resolvi compartilhar com vocês o meu guia de boas práticas para escrever models no Django.

Este guia é fruto da minha experiência, minhas impressões pessoais e também de muita pesquisa sobre o tema. O “definitivo” do título é apenas um click bait! 😬 Nada aqui é definitivo, muito pelo contrário. Essas são as minhas impressões e sua colaboração/questionamento será MUITO BEM VINDA!

Sem mais delongas, vamos ao tópicos:

Nomenclaturas

As boas-práticas de nomenclaturas dos models em Django seguem também as boas práticas da PEP8, que são, basicamente:

  • Nomes de classes são capitalizadas;
  • Nome dos métodos e atributos são em snake_case;

Além disso, os nomes das classes devem ser sempre no singular. Isso se dá pois uma classe model representa um objeto daquele tipo de dado, e não uma coleção.

Resumindo, não faça isso:

Faça isso:

Ordenação dos métodos e atributos

De acordo com a documentação oficial de boas práticas do Django, a ordem indicada para os métodos e atributos de uma classe são:

  • Constantes
  • Campos da tabela
  • Custom Managers
  • classe Meta
  • sobrescrição do __str__()
  • sobrescrição do __save__()
  • definição do get_absolute_url()
  • Properties customizadas
  • Métodos customizados

Parâmetros e funcionalidades do Django

Relações entre Models

Com a possibilidade de criar relações entre models no ORM do Django, temos também a facilidade de integrar essas relações de forma muito simples.

Para toda nova relação criada, o django cria automaticamente um novo método que integra os os models com o sufixo _set. Veja o exemplo:

Se nós usarmos reporter.article_set poderemos manipular todos os artigos associados ao repórter em questão. Entretanto, visualmente isso não é muito agradável. Para resolver o problema, usamos o campo related_name.

Assim, agora podemos fazer:

Além deste parâmetro, temos também o related_query_nameBasicamente o que ele faz é poder alterar a o nome pelo qual você irá fazer uma busca reversa.

No primeiro caso, para fazermos uma busca reversa faríamos:

Mas se quisermos ser mais específicos em dizer que o repórter é na verdade o autor do artigo, então usamos o related_query_name:

Mais um ponto legal de frisar nas relações do Django é que sempre que você tiver uma relação única entre dois elementos, você NÃO DEVE fazer isso:

Ao invés de usar o unique=True, utilize o OneToOneField:

Blanks e Nulls

É importante saber a diferença entre os atributos blank e null.

  • nullé o atributo que corresponde a capacidade do campo aceitar valores nulos no banco de dados. Por padrão, todo campo criado no django não aceita valores nulos.
  • blank: é o atributo responsável por lidar com a entrada deste dado, seja via django-admin ou forms. Você pode ter um campo que aceita valores nulos no banco de dados mas que não aceita uma entrada vazia no seu formulário.

Ainda falando sobre brancos e nulos, vai mais uma dica: Ao usar campos boleanos, não aceite entradas nulas. Para esse caso o django tem um campo específico, que chamado NullBooleanField.

Não faça isso:

Faça isso:

Choices

Diversos campos dos models Django permitem você utilizar o atributo choices. Para usá-los de forma otimizada, as recomendações são:

  • Armazenar strings ao invés de números no banco. (Pode não ser a melhor opção do ponto de vista de performance do banco, porém para fazer filtro vai ser muito mais claro e intuitivo).
  • As variáveis que armazenam as opções devem ser declaradas como constantes, no começo da classe.
  • Se o campo representar o estado do dado, é importante manter uma ordem cronológica. Veja o exemplo.

Mensagens de ajuda

O Django oferece uma facilidade muito boa que é o help_text. Basicamente é um parâmetro que você coloca no campo do seu model e toda a vez que você gerar um formulário baseado neste model ele exibirá a mensagem definida como um texto de ajuda.

O código abaixo:

Irá produzir a seguinte tela no Django Admin:

Lidando com valores monetários

Lidar com moedas é um tema polêmico. A grande complicação está no fator de que a informação, sob a ótica de modelagem de dados, é uma tupla composta do valor com duas casas decimais e a moeda em questão (real, dolar, etc).

Existem projetos que ajudam a lidar melhor com isso, como por exemplo o django-money. Acredito que se o projeto envolver varias moedas diferentes, faça sentido utilizar o projeto.

Caso seja um projeto mais simples, a dica é: Sempre utilize DecimalField, e não FloatField.

Consultando dados de forma correta

Use queryset.count() ao invés de len(queryset)

Quando você utiliza o comando len(queryset)o Django vai carregar todos os ítens em memória para encontrar o tamanho dessa queryset. Quando você utiliza o queryset.count() o Django vai delegar essa função ao banco de dados. Quem você acha que é mais rápido?

Traga somente o dado que você precisa

Veja este código abaixo:

Na prática, se tivermos 10 linhas no banco de dados, o Django vai fazer 11 queries, sendo uma para trazer todos os resultados e depois uma nova query para exibir o nome de cada item. Ruim né?

Agora veja este novo trecho:

Pronto. Somente uma requisição ao banco. Bem melhor né?

Utilize o método .exists()

Lembre-se: as queries python são lazy. Se você utilizar if queryset: para saber se existem elementos na sua query, uma nova consulta no banco de dados será feita. O modo correto de verificar se a query retornou algum elemento é if queryset.exists():.

Não utilize ObjectDoesNotExist

Quando você faz retorna um elemento do banco de dados através do método .get(), caso esse elemento não exista, uma excessão ObjectDoesNotExist vai disparar. Porém a melhor forma de capturar essa excessão não é utilizando esta classe, e sim a classe ModelName.DoesNotExists. Fazendo dessa forma você isola a excessão somente a aquele model.

Modo não recomendado:

 Modo recomendado:

Como testar models?

Este é um tema um pouco mais obscuro. Acredito que aqui exija um pouco de boa prática para o Django em si, um pouco de boa prática de programação, de modo genérico e um pouco de maneirismo do desenvolvedor.

Como gosto de desenvolver utilizando TDD, sempre começo escrevendo o teste. Então, a primeira coisa que testo são os atributos deste model.

Depois de implementar os atributos, eu testo a criação de um elemento:

Por fim, eu testo os métodos customizados implementados, como __str__ e __save__:

Confesso que essa foi a parte que mais tive dúvidas para escrever. Você concorda com esses testes? Discorda? Quero saber sua opinião.

Updates:

Dica extra

Conheça o projeto Django Models Utils. Trata-se de uma série de utilidades para facilitar seu trabalho com os models. Conheça em https://github.com/jazzband/django-model-utils

Referências

  • https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html
  • https://steelkiwi.com/blog/best-practices-working-django-models-python/
  • https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
  • https://realpython.com/testing-in-django-part-1-best-practices-and-examples/#testing-models
  • https://docs.djangoproject.com/en/dev/topics/testing/overview/#assertions

E ai, gostou? Concorda, discorda? Deixa seu comentário e compartilha com a galera.

Abraços